1.介绍
MDX为MultiDimensional Expressions的缩写,多维表达式,是标准的OLAP查询语言。在多数OLAPServer都提供MDX支持,如Microsoft SQL Server OLAP Services,SAS,Hyperion Essbase等。支持多维对象与数据的定义和操作。MDX 在很多方面与结构化查询语言 (SQL) 语法相似,但它不是 SQL 语言的扩展;事实上,MDX 所提供的一些功能也可由 SQL 提供,尽管不是那么有效或直观。
如同 SQL 查询一样,每个 MDX 查询都要求有数据请求(SELECT 子句)、起始点(FROM 子句)和筛选(WHERE 子句)。这些关键字以及其它关键字提供了各种工具,用来从多维数据集析取数据的特定部分。MDX 还提供了可靠的函数集,用来对所检索的数据进行操作,同时还具有用用户定义函数扩展 MDX 的能力。
MDX为多维数据库提供了表达式查询语法,用于查询Cube数据,并提供了许多强大的分析函数,用于支持常用的OLAP分析。
Kingdee OLAP实现了MDX语法,提供了大多数MDX函数,部分函数未实现,因为我们认为当前没有必要实现。本文档后面会提供支持的函数列表。
本指南更像一本入门教程。更为详细的信息可以参考SQLServer OLAP Services联机文档。
2. 基本概念
2.1 Cube结构
在介绍MDX之前,我们简单介绍一下cube结构,理解cube结构是学习MDX的前提。我们采用SQLServer OLAP Services自带的事例OLAP数据库FoodMart来描述。我们建议你阅读《Olap模型设计指南》来学习、熟悉Cube结构。
Cube是联机分析的关键。它们是一种多维结构,包括原始事实数据、聚合数据,这些数据聚合允许用户快速进行复杂查询。
Cube包含两个基本的概念:维度和度量。
维度(Dimension): 维度提供了分类描述,表示一类分析角度,用户通过维度来分析度量数据.
度量(Measures): 度量表示用来聚合分析的数字信息,如数量,销售金额等.
重要: 度量的集合组成了一个特殊的维度,叫做”Measures”.
一个维度可以包含级别的层级结构 级别(Level),表示特定的分类.比如,地区维度可以包含级别层级:Country、State、City。每个级别比它的父级别在数据粒度上更加细粒度。又比如:一个时间维可能包含级别:年、季、月。
成员,是最重要的概念之一。一个成员是维度(包括度量维Measures)上的一个项目值,时间维度上“年”级别的成员可能有2000、2001,月成员有1、2、3等等。
计算成员,是一种运行时通过特殊表达式动态计算的成员。计算成员可以定义为度量。计算成员不影响现有的cube数据,它基于cube数据,通过各种数学表达式和各种函数定义,可以创建复杂的表达式。任何动态分析功能,都可以通过计算成员实现,比如实现占比、同期比等等。
2.3 表达式表示法
维度、级别、成员等,一般用唯一名称UniqueName来标示,可以用[]包围name,如果name有空格或者以数字开头,必须使用[],否则可以忽略。UniqueName是根据层级结构表示的一种方法。即递归显示出祖先的名称。
维度(Dimension):维度直接用[]包围。Product的唯一名称为[Product]或Product,维度Education Level的唯一名称为[Education Level]。度量维为[Measures]。
级别(Level):级别的UniqueName为[维度名称].[级别名称],如[Product].[ Product Family],同样,如果没有空格,[]可以省略,如Product.[Product Family]。
成员(Member):成员的UniqueName格式为[维度].(Parent Member UniqueName).[Member Name],如上面时间维上的2003年2月份的UniqueName为[Time].[1].[2],中间的1为1季度,因为该维度的结构为年、季、月。
度量(Measure):度量实际上是属于度量维的成员。如度量Unit Sales的UniqueName为[Measures].[Unit Sales]。
UniqueName是OLAP元素内部的表示法,在MDX查询语言中,可以使用UniqueName来表示元素。同时,MDX还提供模糊和其它等价的元素标示方式。表现在:
1)省略维度名标示级别,如果一个维度的级别名称在整个Cube中是唯一的,那么可以省略维度名来查询级别。如Product.[Product Family]可以写成[Product Family]。
2)省略维度名标示成员,如果省略维度名,可以标示该维度最高级别的成员,如[Time].[2000]可以写成[2000], [Measures].[Unit Sales]可以写成[Unit Sales].
3)成员挂在级别下,即成员不一定要写成[维度].(Parent Member UniqueName).[Member Name],可以写成[维度].[级别].[Member Name].如2000年3月可以写成[Time].[Months].[3]
模糊查询表示法,都基于不会重复的假设,如果有重复的元素,取第一个查找到的元素作为查询结果,可能发生错误.因此,建议使用完备的表示法.
2.4元组、集合
元组用于定义来自多维数据集的数据切片;它由来自一个或多个维度的单个成员的有序集合组成。元组内不能包含来自同一个维度的多个成员(是否可以理解为坐标?).元组用()包围.如:
(时间.[下半年])
(时间.[下半年],[产品].[手机].[Nokia])
如果一个元组是由单个维度的成员组成,那么可以不用()包围,即(时间.[下半年])可表示成:时间.[下半年]
集合(set)是零个、一个或多个元组的有序集合。集合最常用于在 MDX 查询中定义轴维度和切片器维度,并且同样可能只具有单个元组或可能在某些情况下为空。在 MDX 语法中,元组用花括号括起来以构造集合,下面的示例显示具有两个元组的集合:
{ (时间.[上半年], 路线.非陆地.航空), (时间.[下半年], 路线.非陆地.海路) }
一个集合可包含同一个元组不止一次的出现。下面的集合是可接受的:
{ 时间.[下半年], 时间.[下半年] }
集合指以元组表示的一组成员组合,或指集合中的元组所代表的单元中的值,视集合使用的上下文而定。
注意,单个元组的集合不等于元组。如{时间.[下半年]}不等于 时间.[下半年].
在MDX语法中,很多函数语义中包含元组和集合,作为参数或者返回值。
3. MDX查询与语义
3.1 MDX基本查询
先看看MDX基本语法结构:
SELECT [axis specification] ON COLUMNS,[axis specification] ON ROWS FROM [cube name]
WHERE [slicer specification]
[axis specificatioin]可以看成是轴的成员选择。[slicer specification]表示切片上的成员,可以看成过滤信息,[slicer specification]可选,如果没有指定,取系统默认的维度成员作为切片。
3.2 轴维度和切片器维度
当设计多维表达式 (MDX) 查询时,应用程序一般查看多维数据集并将维度集合划分为两个子集:
•轴维度,为多个成员检索数据的维度。
•切片器维度,为单个成员检索数据的维度。
因为轴维度和切片器维度都可从要查询的多维数据集的多个维度构造,所以用这些术语将要查询的多维数据集使用的维度与在由 MDX 查询返回的多维数据集中创建的维度区分开。
例如,假定存在名为 TestCube 的多维数据集,具有两个名为 Route 和 Time 的简单维度。因为多维数据集的度量值是 Measures 维度的一部分,所以该多维数据集总共有三个维度。查询要提供一个矩阵,可以在该矩阵内跨路线和时间比较 Packages 度量值。
在下面的 MDX 查询示例中,Route 和 Time 维度用作轴维度,Measures 维度用作切片器维度。Members 函数表明要用于构造集合的维度或级别的成员,而不必在 MDX 查询中显式声明给定维度或级别的各个成员。
SELECT
{ Route.nonground.Members } ON COLUMNS,
{ Time.[1st half].Members } ON ROWS
FROM TestCube
WHERE ( [Measures].[Packages] )
指定轴维度的内容
轴维度决定多维结果集的边缘。多维表达式 (MDX) 使用 SELECT 子句通过将集合指派到特定轴来指定轴维度。以下信息描述在 MDX 中怎样处理这种指派。
在下面的语法示例中,每个 <axis_specification> 值定义一个轴维度。数据集中轴的个数等于多维表达式 (MDX) 查询中 <axis_specification> 值的个数。MDX 查询最多可以支持 128 个指定轴,但几乎没有 MDX 查询会用到 5 个以上的轴。
<axis_specification> 语法可分解为:
<axis_specification> ::= <set> ON <axis_name>
<axis_name> ::= COLUMNS | ROWS
轴维度上的只能接受集合<set>,如果是手工指定成员集合,必须用{}包围,如果使用MDX集合函数,则不需要用{}包围,因为集合函数返回值为集合。一个轴维度上可以包含几个维度,如:
SELECT {
[Measures].[Sales_Dollars], [Measures].[Sales_Units], [Measures].[Sales_Units_max]
}
ON columns,
CrossJoin(
{[State].[Canada], [State].[Mexico], [State].[USA]},
{[Product].[Bread], [Product].[Dairy], [Product].[Meat]}
)
ON rows
FROM sales
WHERE ([Time].[All Time], [Employee].[All Employee])
Columns轴上是手工指定的成员元组集合,用{}包围,Rows轴使用集合函数CrossJoin,该函数返回两个集合的交集,Rows轴上包含两个维度State和Product。
指定切片器维度的内容
切片器维度筛选多维数据。可以通过将切片器维度包含在多维表达式 (MDX) 查询的 WHERE 子句来限制所返回的数据。
假定未显式指派给轴的维度是切片器维度,并用其默认成员进行筛选。则默认成员为最高级别的第一个成员。
切片器维度还可通过使用 MDX 语法的 WHERE 子句进行显式指定。WHERE 子句的语法可分解为:
[WHERE [<slicer_specification>]]
切片器维度只可接受评估为单个元组的表达式。如下例所示:
WHERE ( [Time].[1st half], [Route].[nonground] )
3.3 高级查询-使用计算成员
基本MDX查询提供了对多维数据的简单查询,MDX查询还提供了更为丰富强大的多维查询工具。
计算成员允许在查询表达式中定义公式,并将该公式当成一个新的成员,挂在某个维度下。它并非通过检索数据来解析,而是通过计算 MDX 表达式来返回值。在 MDX 查询中构造和使用计算成员的能力为多维数据提供了大量操作功能。多数分析功能都可以通过计算成员来实现。
MDX通过With语句来创建计算成员,下面的语法用于将 WITH 关键字添加到 MDX SELECT 语句:
通过在 Format_String中指定计算成员的格式化串,跟Cube定义中的Measure定义的formatString一样,采用java.text.DecimalFormater中的格式化语法。
例如,下面的 MDX 查询示例定义了两个计算成员。第一个计算成员 [Measures].[StoreType] 用于表示 Store Type 成员属性。第二个计算成员 [Measures].[ProfitPct] 用于计算给定商店的总利润率,并将其表示为格式化的百分比值。
第二个计算成员 [Measures].[ProfitValue] 使用第一个计算成员 [Measures].[ProfitPct] 中创建的值来生成自己的值。
只能是后面的计算成员使用前面的计算成员,不能反过来,所有,计算成员的顺序很重要。
3.4 高级查询-使用命名集合
命名集合是一个与别名相关联的集合表达式。它定义一个集合,可以在MDX语句中多出使用,主要是为了方便维护,提高可读性,如果该集合被多处使用,可以重用,减少解析时间,提高性能。命名集别名视为集合表达式,并可用于任何接受集合表达式的地方。
下面的语法用于将 WITH 关键字添加到 MDX SELECT 语句:
[WITH <formula_specification>]
[, <formula_specification>]
SELECT [<axis_specification>
[, <axis_specification>...]]
FROM [<cube_specification>]
[WHERE [<slicer_specification>]]
命名集的 <formula_specification> 值进一步分解为以下语法定义:
<formula_specification> ::= SET <set_name> AS '<set>'
<set_name> 参数包含命名集的别名。<set> 参数包含命名集别名所指的集合表达式。
例如,[ChardonnayChablis] 命名集用于Product 维度上的所有 Chardonnay 酒和 Chablis 酒成员。以下示例对命名集的语法进行了描述:
WITH SET [ChardonnayChablis] AS
'{[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Good].[Good Chardonnay],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Pearl].[Pearl Chardonnay],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Portsmouth].[Portsmouth Chardonnay],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Top Measure].[Top Measure Chardonnay],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Walrus].[Walrus Chardonnay],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Good].[Good Chablis Wine],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Pearl].[Pearl Chablis Wine],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Portsmouth].[Portsmouth Chablis Wine],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Top Measure].[Top Measure Chablis Wine],
[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Walrus].[Walrus Chablis Wine]}'
还可在用于创建命名集的集合表达式中使用 MDX 函数。