分享

另类MDX学习记要

 kittywei 2011-11-03
本文作者:donegal 转载请注明出处:murdercdh.tianya.cn
  有错误的地方请给我E-Mail:murdercdh@126.com
  
开篇
  对于数据挖掘与商业智能这一块内容,Sql Server提供了一整套的解决方案,本着易用,快速的原则,将大部分东西都集成到了SSAS当中,作为中小企业实施BI首选。
  在这里我想重要讲解的是在SSAS当中非常重要的一个环节,MDX语言。
  学习新的技术,就好像拿到了一本新的武功图谱,过程总是充满激情,思维的互相碰撞,使整个过程充满悬念,当然可能长时间修炼可能造成枯燥,厌恶,但是为了成为一代大侠,这个过程是原始的积累和学习过程,不可跳跃,除非你是自创武功,独成一派,这样的功力至少需要差不多几十年的积累,张三疯不是一百岁才创太极么?所以各位安身修炼,切不可急躁。
  
总诀式
  首先给出定义:多维表达式 (MDX) 是一种功能完备、基于语句的脚本语言,用于定义、使用以及从 Microsoft SQL Server 2005 Analysis Services (SSAS) 中的多维对象中检索数据。
  MDX 提供以下几种语言功能:
  1. 用于创建、删除以及使用多维对象的数据定义语言 (DDL) 语句。
  2. 用于从多维对象中检索操作数据的数据操作语言 (DML) 语句。
  3. 用于管理作用域、上下文以及 MDX 脚本内的流控制的脚本语言语句。
  4. 用于操作从多维对象中检索的数据的大量运算符和函数。
  要想深入的了解这种语言所带来的巨大优势和遍历,首先需要对整个SSAS的框架体系做一个大致的了解,这样才能更加深入的了解MDX的强大功能以及复杂程度。
  Microsoft SQL Server 2005 Analysis Services (SSAS) 使用服务器组件和客户端组件为商业智能应用程序提供联机分析处理 (OLAP) 和数据挖掘功能:
  
六大心法秘诀:练功者必须仔细体会,待小有所成,亦可不断体会,必有所得。
  
特性1:Analysis Services 的服务器组件作为 Microsoft Windows 服务来实现。SQL Server 2005 Analysis Services 支持同一台计算机中的多个实例,每个 Analysis Services 实例作为单独的 Windows 服务实例来实现。
  
  特性2:客户端使用公用标准 XML for Analysis (XMLA) 与 Analysis Services 进行通信,XMLA 是一个基于 SOAP 的协议,用于发出命令和接收响应,公开为一项 Web 服务。此外,客户端对象模型通过 XMLA(包括托管提供程序 (ADOMD.Net) 和本机 OLE DB 访问接口)进行提供。
  
  特性3:查询命令可使用下列方式发出:SQL;多维表达式 (MDX)(一种面向分析的行业标准查询语言);或数据挖掘扩展插件 (DMX)(一种面向数据挖掘的行业标准查询语言)。还可以使用 Analysis Services 脚本语言 (ASSL) 来管理 Analysis Services 数据库对象。
  
  特性4:Microsoft SQL Server 2005 Analysis Services (SSAS) 支持瘦客户端体系结构。Analysis Services 计算引擎完全基于服务器,因此,所有查询都在服务器上进行解析。因此,每个查询只需在客户端和服务器之间进行一次来回行程,从而使得性能可以随着查询复杂性的增加而伸缩。
  
  特性5:Analysis Services 的本机协议为 XML for Analysis (XML/A)。Analysis Services 为客户端应用程序提供了数个数据访问接口,但是所有这些组件都使用 XML for Analysis 与 Analysis Services 实例进行通信。
  
  特性6:Analysis Services 提供了数个不同的访问接口,以支持不同的编程语言。访问接口借助 Internet 信息服务 (IIS),并通过 TCP/IP 或 HTTP 发送和接收 SOAP 数据包中的 XML for Analysis 来与 Analysis Services 服务器进行通信。HTTP 连接使用由 IIS 实例化的 COM 对象(称为数据抽取),该对象充当 Analysis Services 数据的管道。数据抽取既不会以任何方式检查包含在 HTTP 流中的基础数据,也不会检查可用于数据库本身中任何代码的任何基础数据结构。
  
  对于ssas有了一个大体的了解以后,就可以开始对具体的mdx语言开始进行学习了。对于一些基础的概念,会穿插到里面进行解释,这样大家就比较容易理解。
  
  下面介绍本门武功的基础概念,这样将有住于练习者领会其中内容,切记,基础乃练功之根本,务必正确领会,否则就像当年梅超疯理解偏差,错炼九鹰白骨爪,终究难成正果。
  下面用一个cube例子来解释基础的语言和概念:
  关系数据库以二维平面表的形式组织数据。这些表有一个列维度和一个行维度。在每个行和列的交点处只有一个数据元素。
  而多维数据库则不同,它是基于称为“多维数据集”的结构,如下图所示。多维数据集按“层次结构”组织数据,而不是以表的形式组织数据。
  
  成员:
  成员是维度中的一个项目,表示数据的一次或多次出现。可将维度中的成员看作基础数据库中的一个或多个记录,该记录在此列中的值属于此类别。成员是描述多维数据集中的单元数据时的最低级别的引用。
  可以用成员名称或成员键引用某个成员。在上一示例中,用成员在 Time 维度中的名称 4th quarter 来引用该成员。但是,如果维度不具有非唯一的成员名称,则成员名称可以重复,也可以更改渐变维度中的成员名称。
  引用成员的另一种方法是引用成员键。维度使用成员键明确标识特定成员。在 MDX 中,“与”符号 (&) 用于区分成员键和成员名称。例如,以下引用使用 4th quarter 成员的成员键 Q4:
  [Time].[2nd half].&[Q4]
  
  元组:
  包含在多维数据集中的数据元素称为“单元”。通过对多维数据集中包含的每个属性层次结构指定一个成员可以唯一地标识一个单元。标识一个单元的属性的组合称为“元组”。
  元组标识多维数据集中的单元。一个元组由多维数据集中每个层次结构中的一个成员组成(显式或隐式引用)。如果特定层次结构中的成员没有在元组中显式引用,则该层次结构中的默认成员将隐式包含在元组中。
  在 MDX 中,元组根据其复杂性依照语法进行构造。如果元组只由一个层次结构中的一个成员组成(通常称为“简单元组”),则下列语法是可以接受的:
  Time.[2nd half]
  例如,下面的元组标识了上图中值为 240 的一个单元(因为这里有四个维度,所以四维定义一个元组):
  ( Source.[Eastern Hemisphere].Africa,
  Time.[2nd half].[4th quarter],
   Route.Air,
   Measures.Packages)
  
  正如可以指定从关系数据库的表中检索多组列或行一样,您可以指定从多维数据集中检索一组元组。MDX 中用来指一个有序的元组集合的标识符称为“集”。下面的示例标识了上图所示的多维数据集中的一个元组集:
  
  { (Time.[1st half].[1st quarter]),
   Time.[2nd half].[3rd quarter]) }
  
  集:
  集是零个、一个或多个元组的有序集合。集最常用于定义 MDX 查询中的查询轴和切片器轴,因此可以只有一个元组,在某些情况下,也可以为空。下面的示例显示了具有两个元组的集:
  { (Time.[1st half], Route.nonground.air), (Time.[2nd half], Route.nonground.sea) }
  好了,了解完了这些基本的概念以后就可以正式开始使用mdx语句来获取你想要的数据了,
  
  具体的语句看起来和sql的语句差不多,查询的思路也差不多,但是所有的数据都要以上面的概念去理解,而不是简单的一维度和二维度的,而是多维的,所以要用集合,元组,成员这些概念去理解,一开始接触的人理解起来可能会比较困难,不过慢慢的就可以加深理解了。
  
  下面我们就用几条比较经典的语句来摡略的学习整个mdx的语法,这样的学习方式可能会遗漏许多细节的地方,但是对于快速入门,那是绝对有好处的,在使用熟练度达到一定要求以后,就可以查阅sdk对一些细节的地方进行处理。
  
  内功心法和总诀式这里就介绍完毕了,下面开始具体的招数,每一招分为许多层次,由简单到复杂,切不可急功近利,一定要着重招式的基础部分的领悟,否则很容易走火入魔。
  
  第一式:查询语句
  第一层:
  SELECT
   { Route.nonground.Members } ON COLUMNS,
   { Time.[1st half].Members } ON ROWS
  FROM TestCube
  
  这条语句很简单,就是从Adventure Works里面查询出mesaures维度下的members成员,所查询出来的属性集作为列,而下面的这个Product.Style.CHILDREN属性集作为行。
  
  提示:这里存在三个细节扩展需要注意:
  第一个是成员的限定,可以在 MDX 查询中使用 WITH 关键字
  第二个是成员的的函数,可用于检索其他 MDX 实体(如维度和级别)中的成员
  第三个是查询轴内容和切片器轴内容的查询:
  具体的在大家深入以后就会有一个了解。
  第二层:
  SELECT
   [Measures].[Special Discount] on COLUMNS,
   NON EMPTY [Product].[Product].MEMBERS ON Rows
  FROM [Adventure Works]
  WHERE [Product].[Category].[Bikes]
  
  这里多加了一个where语句,看似和sql语句差不多,但是理念是不一样的,需要了解下面二个概念:
  查询轴:查询轴用于指定由多维表达式 (MDX) SELECT 语句所返回的单元集的范围。通过指定单元集的范围可以限定客户端可以看到的返回数据。
  切片器轴:切片器轴将对多维表达式 (MDX) SELECT 语句返回的数据进行筛选,限定返回的数据,从而只返回与指定成员相关的数据。切片器轴是在 MDX 中 SELECT 语句的 WHERE 子句中定义的
  每个 MDX 查询都在指定的多维数据集上下文中执行。此上下文定义了由该查询中的表达式求值的成员。
  在 SELECT 语句中,FROM 子句用于确定多维数据集上下文。此上下文可以是整个多维数据集,也可以只是该多维数据集的一个子多维数据集。如果通过 FROM 子句指定了多维数据集上下文,就可以使用其他函数来扩展或限制该上下文。
  
  第三层:
  WITH SET [ChardonnayChablis] AS
   'Filter([Product].Members, (InStr(1, [Product].CurrentMember.Name, "chardonnay") <> 0) OR (InStr(1, [Product].CurrentMember.Name, "chablis") <> 0))'
  SELECT
   [ChardonnayChablis] ON COLUMNS,
   {Measures.[Unit Sales]} ON ROWS
  FROM Sales
  
  第四层:
  create Session set [Store].[SetCities_2_3] as
  {[Data Stores].[ByLocation].[State].&[CA].&[City 02],
  [Data Stores].[ByLocation].[State].&[NH].&[City 03]}
  这里的第三层和第四层属于同一内容的两个不同方面,应该联系起来学习相互对照,这样可以对这个招术有一个比较深刻的记忆和理解。
  查询作用域:若要创建一个命名集,该命名集被定义为 MDX 查询的一部分并且其作用域因此被限制在该查询内,请使用 WITH 关键字。然后,就可以在 MDX SELECT 语句中使用该命名集。通过这种方法,更改用 WITH 关键字创建的命名集时就不会打乱 SELECT 语句。
  会话作用域:若要创建一个命名集,使其作用域比查询上下文更广(即,其作用域为 MDX 会话的生存期),请使用 CREATE SET 语句。使用 CREATE SET 语句定义的命名集对该会话中的所有 MDX 查询均可用。例如,CREATE SET 语句对于需要在多种查询中大量重用某个集的客户端应用程序会非常有用。
  
第五层:
  WITH
   MEMBER [Measures].[Special Discount] AS
   [Measures].[Discount Amount] * 1.5
  SELECT
   [Measures].[Special Discount] on COLUMNS,
   NON EMPTY [Product].[Product].MEMBERS ON Rows
  FROM [Adventure Works]
  WHERE [Product].[Category].[Bikes]
  这里糅合了前面几层的东西,但是增加了表达式的计算元素,修炼者需要掌握前面级别,方可轻松领悟这一层次。
  这里的on colums和on rows的限定,可以用axis函数来代替,他们所表达的意义是相同的,在axis当中,以下数字分别代表不同的维度界定。
  0 Columns
  1 Rows
  2 Pages
  3 Chapters
  4 Sections
  这里需要注意的是如果要采用1,那么必须采用0,如果要采用3,那么必须采用了0,1和2,这里的维度是逐级构造的,不能跳跃。
  
第六层:
  Create Session Member [Store].[Measures].LastFourStores as
  sum(([Stores].[ByLocation].Lag(3) :
  [Stores].[ByLocation].NextMember), [Measures].[Units Sold])
  采用内部成员属性:定义内部成员数次女冠以供使用.
  SELECT
   CROSSJOIN([Ship Date].[Calendar].[Calendar Year].Members,
   [Measures].[Sales Amount]) ON COLUMNS,
   NON EMPTY Product.Product.MEMBERS
   DIMENSION PROPERTIES
   Product.Product.[List Price],
  
   Product.Product.[Dealer Price] ON ROWS
  FROM [Adventure Works]
  WHERE ([Date].[Month of Year].[January])
  这里写了二条语句,第一条的特殊之处在于使用了功能函数对数据成员进行了操作,而后面的一条带cross join的语句记忆后面的DIMENSION PROPERTIES
  ,涉及到了高级招式的一些细节,在这里不推荐大家练习,待练到后面的招式,这一招自然会融会贯通,切不可操之过急。
  
  小结:
  从以上的几个语句,大家可以很好的看到mdx语句以及他的特性,很多细节的东西都在里面了,整个过程是一个由简单到复杂,由主题到细节的过程,具体的还得大家在实际运用中慢慢体会。
  Ps:第一式里面的层级就只有六层,一次修炼,不断演练,可达到熟练运用的境界,对于本心法,实战当中用的最多的可能就是第一式里面的东西,所以各位修练者务必做到能构熟练运用。
  
  第二式:功能函数
  这一层的描述,包含了许多细节的功能函数,这些函数对于在聚合,整合数据的时候起到很大的作用。
  第一层:
  SELECT Measures.[Internet Sales Amount] ON COLUMNS,
   CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
   {[Customer].[Country].MEMBERS}) on ROWS
   FROM [Adventure Works]
  这里添加了一个特殊的CrossJoin,其实是对里面的两个成员组的做笛卡尔集,之后再聚合数据。做笛卡尔集的时候有些单元可能是空的,所以有了后面的招数,负责清空空的单元。
  
  第二层:
  SELECT Measures.[Internet Sales Amount] ON COLUMNS,
   NonemptyCrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
   {[Customer].[Country].MEMBERS},Measures.[Internet Sales Amount],2 ) on ROWS
   FROM [Adventure Works]
  
  SELECT Measures.[Internet Sales Amount] ON COLUMNS,
   Nonempty (CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
   {[Customer].[Country].MEMBERS}),Measures.[Internet Sales Amount]) on ROWS
   FROM [Adventure Works]
  这里有二种方式实现,一种是直接采用原来2000版本的函数NonemptyCrossJoin,还有一种是后来2005新增的函数联用。
  
  第三层:
  SELECT Measures.[Internet Sales Amount] ON COLUMNS,
   Filter (CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
   {[Customer].[Country].MEMBERS}),[Internet Sales Amount] >2000000) on ROWS
   FROM [Adventure Works]
  这里采用了filter函数,对查询出来的数据集进行条件的筛选。后面的
  [Internet Sales Amount] >2000000 就是负责限定值在200000以上进行聚合操作。
  
  第四层:
  WITH MEMBER Measures.CustomerCount AS DistinctCount (
   Exists ([Customer].[Customer].MEMBERS,[Product].[Product Line].Mountain,
   "Internet Sales"))
   SELECT Measures.CustomerCount ON COLUMNS
   FROM [Adventure Works]
  这里同样也是用来筛选数据的,exists用户筛选出数据,后面的Internet Sales,就是筛选的条件。
  
  第三式:作用域限定
  第一层:
  CALCULATE 语句
  使用 Business Intelligence Development Studio 创建多维数据集时,CALCULATE 语句会自动作为第一个语句包含在多维数据集的 MDX 脚本中。CALCULATE 语句通知多维数据集中的每个单元从粒度较小的单元开始聚合。聚合单元后,如果随后使用表达式填充粒度较小的单元,则会影响粒度较大的单元的聚合值。
  有效的多维表达式 (MDX) 子多维数据集表达式。
  如果用多个赋值计算某个单元,而且赋值相互重叠且可比较(也就是说,两个子多维数据集都具有较高、较低或相同的粒度),则最后传递的赋值在重叠区域具有优先权。例如,运行以下 CALCULATE 语句
  Calculate;
  ({Week.1, Week.2}, Month.Jan) = 20;
  ({Week.2, Week.3}, Month.Jan) = 40;
  运行此 CALCULATE 语句将计算 (Week.All, Month.Jan) 的值,该值等于 20 + 40 + 40 + Week.1 到 Week.3 之外的任何事实数据。
  
  第二层:
  This 函数使您可以在 MDX 脚本内检索当前的子多维数据集。您可以使用 This 函数快速将当前子多维数据集内的单元的值设置为 MDX 表达式。在特定计算传递过程中,通常将 This 函数和 SCOPE 语句一起使用,以更改特定子多维数据集的内容。
  SCOPE([Customer].&[Redmond].MEMBERS,
  [Measures].[Amount], *);
  THIS = [Measures].[Amount] * 1.1;
  END SCOPE;
  SCOPE 语句定义包含 MDX 脚本内其他 MDX 表达式和语句并指定这些表达式和语句的作用域的当前子多维数据集。MDX 在该子多维数据集的上下文内计算其他 MDX 表达式和语句,包括 This 函数和 CALCULATE 语句。
  SCOPE 语句本质上是动态的,但不是迭代的。SCOPE 语句中包含的语句运行一次,但子多维数据集本身可以动态确定。例如,有一个名为 SampleCube 的多维数据集。对 SampleCube 多维数据集应用以下 SCOPE 语句以定义一个子多维数据集,将上下文定义为 Measures 维度内的 ALLMEMBERS:
  SCOPE([Measures].ALLMEMBERS);
  THIS = [Measures].ALLMEMBERS.COUNT;
  END SCOPE;
  
  此 SCOPE 语句中包含的语句和表达式运行一次。
  现在,商业用户对 SampleCube 多维数据集运行以下 MDX 查询,该查询包含一个名为 ExistingMeasure 的度量值:
  
  WITH MEMBER [Measures].[NewMeasure] AS '1'
  SELECT
  [Measures].ALLMEMBERS ON COLUMNS,
  [Customer].DEFAULTMEMBER ON ROWS
  FROM
  [SampleCube]
  
  第三层:
  在 Adventure Works DW 示例多维数据集的 Finance 度量值组中,以下 MDX 脚本示例使用 SCOPE 语句将 Customer 维度中 Redmond 成员的子级的 Amount 度量值的值设置为比原来增加 10%。但是,另一个 SCOPE 语句将子多维数据集更改为包含 2002 日历年子级的 Amount 度量值。最后,仅为该子多维数据集聚合 Amount 度量值,其他日历年中 Amount 度量值的聚合值则保持不变。
  
  CALCULATE;
  SCOPE([Customer].&[Redmond].MEMBERS,[Measures].[Amount], *);
  THIS = [Measures].[Amount] * 1.1;
  END SCOPE;
  
  第四层:
  SELECT Measures.[Internet Sales Amount] on COLUMNS,
   TOPCOUNT ([Product].[Product Categories].[SubCategory].Members,
   10, Measures.[Internet Sales Amount]) ON ROWS
   from [Adventure Works]
   WHERE ([Customer].[Customer Geography].[Country].&[United States])
  这里的函数定义了获取聚合值数量,这个函数负责获取聚合出来的前10个值。
  
  第五层:
  允许您有条件地从多个比较中返回特定的值。有两种类型的 Case 语句:
  简单 Case 语句将某个表达式与一组简单表达式进行比较,以返回特定的值。
  搜索 Case 语句计算一组布尔表达式,以返回特定的值。
  Case 搜索表达式
  若要使用 Case 表达式执行更为复杂的计算,请使用 Case 搜索表达式。使用此搜索表达式的变体可以计算输入表达式是否位于一个值范围内。MDX 按 WHEN 子句出现在 CASE 语句中的顺序计算这些子句。
  简单 Case 表达式
  MDX 通过将 input_expression 解析为标量值来计算简单 Case 表达式。然后,将该标量值与 when_expression 的标量值进行比较。如果这两个标量值匹配,则 CASE 语句返回 when_expression 的值。如果这两个标量值不匹配,则计算下一个 WHEN 子句。如果所有的 WHEN 子句计算结果均为 False,则返回 ELSE 子句的值(如果存在 ELSE 子句)。
  
  下例中,为每个 WHEN 子句针对指定的 Boolean_expression 计算 Reseller Order Count 度量值。根据每年的 Reseller Order Count 度量值的值返回一个结果。因为按照 WHEN 子句出现的顺序计算这些子句,所以可简单地将所有大于 6 的值赋值为“VERY LARGE”,而无需显式地指定每个值。对于没有在 WHEN 子句内指定的 Reseller Order Count 值,则返回 else_result_expression 的标量值。
  
  WITH MEMBER [Measures].x AS
  CASE
  WHEN [Measures].[Reseller Order Count] > 6 THEN 'VERY LARGE'
  WHEN [Measures].[Reseller Order Count] > 4 THEN 'LARGE'
  WHEN [Measures].[Reseller Order Count] > 2 THEN 'MEDIUM'
  WHEN [Measures].[Reseller Order Count] > 0 THEN 'SMALL'
  ELSE "NONE"
  END
  SELECT Calendar.[Calendar Year] on 0,
  NON EMPTY [Geography].[Postal Code].Members on 1
  FROM [Adventure Works]
  WHERE [Measures].x

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多