28 编写 MDX 查询
MDX 是一种类似 SQL 的语言,可用于发出从 Essbase 检索数据的查询。MDX 还用于在 ASO 多维数据集上定义公式、查询元数据、限定成员名称以及划定数据或元数据的子集。学习 MDX 的最佳方法是编写查询。
本节通过在一系列练习中编写针对 Sample Basic 多维数据集的查询来帮助您学习 MDX。
编写 MDX 查询的先决条件
要完成练习,您需要:
-
文本编辑器,用于编写 MDX 查询。
-
使用 Sample Basic 访问 Essbase 实例。
如果需要获取 Sample Basic,请按照 Create a Sample Cube to Explore Outline Properties 中的步骤操作(只需执行导入,然后跳过设置大纲属性)。
-
MaxL Client ,向 Essbase 发出查询。
构建 MDX 查询模板
了解 MDX 查询的基本格式,以便您可以开始将 MDX 与 Essbase 一起使用。与 SQL 语句类似,MDX 查询通常以 SELECT 开头。
在本节中,您将创建一个模板,用作开发简单 MDX 查询的基础。
大多数查询可以基于以下语法框架构建:
SELECT
{}
ON COLUMNS
FROM Sample.Basic第 1 行中的 SELECT 关键字开始于 MDX 语句的主体。
第 2 行中的大括号 { } 是 set 的占位符。在上面的查询中,集合为空,但大括号仍保留为占位符。
练习 1:创建 MDX 查询模板
要创建查询模板,请执行以下操作:
-
创建一个文件夹来存储可针对 Sample.Basic 多维数据集运行的示例查询。
-
使用文本编辑器,在空白文件中键入以下代码:
SELECT {} ON COLUMNS FROM Sample.Basic -
将该文件另存为
qry_blank.txt。
MDX 集和元组
编写第一个查询,然后在 MaxL Client 中运行该查询,以从 Sample Basic 多维数据集检索某些数据。
集
MDX 集可以为空,也可以是元组集合或集集合。
例如,以下是空集。
{ }集合必须用大括号 {} 括起来,除非集合由返回集合的 MDX 函数表示(有关稍后函数的详细信息)。
下面是一个由一个元组组成的集合。
{[Cola]}
在以下查询中,{([Cola], [Actual])} 也是由一个元组组成的集合,不过在这种情况下,元组具有多个成员名称。
SELECT
{([Cola], [Actual])}
ON COLUMNS
FROM Sample.Basic{([Cola], [Actual])} 是由两个维(产品和方案)中的两个成员(可乐和实际)组成的元组。
维度规则
当一个集具有多个元组时,每个元组的成员必须以相同的顺序表示相同的 Essbase 维。也就是说,所有元组的维数必须与其他元组相同。
-
正常:以下集合由具有相同维度的两个元组组成:
{(West, Feb), (East, Mar)} -
不确定:以下集打破了维数规则,因为 Feb 和 Sales 来自不同的维:
{(West, Feb), (East, Sales)} -
不确定:以下集打破了维数规则,因为尽管两个元组包含相同的维,但维的顺序在第二个元组中反转:
{(West, Feb), (Mar, East)}
元组和成员名称
元组是一种从任意数量的维引用成员或成员组合的方式。例如,在 Sample.Basic 多维数据集中,所有这些都是有效的元组:
Jan(Jan, Sales)([Jan],[Sales],[Cola],[Utah],[Actual])
可以通过以下方式指定成员名称:
-
通过指定实际名称或别名;例如:
-
Cola -
Actual -
COGS -
[100]
如果成员名称以数字开头或包含空格,则该名称应位于括号内;例如,
[100]或[New York]。但是,建议为所有成员名称使用成员名称方括号,以提高清晰度和代码可读性。如果成员名称以“和”号 (&) 开头,则该名称应使用引号;例如
["&xyz"]。这是因为前导和符号是为替代变量保留的(请参见 Variables in MDX Queries )。您也可以将其指定为StrToMbr("&100")。对于属性成员,应使用长名称(限定为唯一标识成员);例如,
[Ounces_12]而不是[12]。 -
-
通过将维名称或任何祖先成员名称指定为成员名称的前缀,例如
[Product].[100-10]和[Diet].[100-10]。建议针对所有成员名称使用此练习,因为它可以消除歧义,并允许您准确地引用共享成员。请参阅大纲中的重复成员名称中的“具有区分祖先资格的成员”。注意:
在成员名称限定中不要使用多个祖先。如果包含多个祖先,则 Essbase 将返回错误。例如,
[Market].[New York]和[East].[New York]是纽约的有效名称;但是,[Market].[East].[New York]返回错误。 -
通过指定在 WITH 部分中定义的计算成员的名称。
练习 2:运行第一个查询
请记住,查询模板第 2 行中的大括号 {} 是集的占位符。在本练习中,我们将向查询添加一个集并运行它。
要运行查询,请执行以下操作:
-
打开
qry_blank.txt,这是您从构建 MDX 查询模板创建的查询模板。 -
因为集可以像一个元组一样简单,所以在大括号
{ }中添加用于保存集的元组。在第 2 行中的
{ }大括号内键入[Jan]:SELECT {[Jan]} ON COLUMNS FROM Sample.Basic -
将查询另存为
qry_first.txt。 -
确保 Essbase 正在运行。
-
启动 MaxL Client 并使用有效的用户名和密码登录。例如:
login admin1 my_Pa55w0rD on "https://myserver.example.com:9001/essbase/agent"; -
将整个 SELECT 查询复制并粘贴到 MaxL Client 中,但尚未按 Enter 键。
-
在 "Basic" 之后的任何位置,但在按 Enter 之前输入一个分号。(分号不是 MDX 要求,但 MaxL Client 要求它指明语句的结尾。)
-
按 Enter 键将查询发送到 Essbase 。
结果应类似于以下内容:
Jan 8024
具有轴和多维数据集规范的 MDX 查询布局
MDX 轴是用于整理来自 Essbase 多维数据集的查询结果网格布局的指令。ON COLUMNS 和 ON ROWS 是描述结果显示位置的轴关键字。多维数据集规范包括 FROM 关键字,并告知 Essbase 要查询的多维数据集。
MDX 轴
选择后,轴适合 MDX 查询:
SELECT <axis> [, <axis>...]
FROM <database> 在以下查询中,轴规范为 {Jan} ON COLUMNS:
SELECT
{Jan} ON COLUMNS
FROM Sample.Basic必须在任何 MDX 查询中至少指定一个轴。
最多可指示 64 个轴,从 AXIS(0) 开始并继续使用 AXIS(1)...AXIS(63)。使用三个以上的轴是不常见的。轴的顺序并不重要;但是,如果指定一组轴 0 到 n,则不应跳过介于 0 和 n 之间的轴。此外,维不能出现在多个轴上。
前五个轴具有关键字别名,如下表所示:
表 28-1 轴关键字别名
| 轴关键字别名 | 轴 |
|---|---|
|
在列上 |
可用于代替 AXIS(0) |
|
在行上 |
可以替换 AXIS(1) |
|
在页面上 |
可更换 AXIS(2) |
|
关于章节 |
可以替换 AXIS(3) |
|
部分 |
可更换 AXIS(4) |
MDX 多维数据集规范
多维数据集规范是确定要查询的 Essbase 数据库的查询的一部分。多维数据集规范适合 MDX 查询,如下所示:
SELECT <axis> [, <axis>...]
FROM <cube> <cube> 部分在 FROM 关键字之后,应由分隔或非分隔的标识符组成,这些标识符首先指定应用程序名称,然后指定数据库名称;例如,以下规范有效:
-
FROM Sample.Basic -
FROM [Sample.Basic] -
FROM [Sample].[Basic] -
FROM'Sample'.'Basic'
练习 3:运行双轴查询
要运行双轴查询,请执行以下操作:
-
打开
qry_blank.txt,即您在构建 MDX 查询模板中创建的查询模板。 -
在
ON COLUMNS之后添加逗号;然后通过添加ON ROWS为第二个轴添加占位符:SELECT {} ON COLUMNS, {} ON ROWS FROM Sample.Basic -
将新查询模板另存为
qry_blank_2ax.txt。 -
作为列轴的集合规范,输入 Product 成员 100-10 和 100-20。例如:
SELECT {[100-10],[100-20]} ON COLUMNS, {} ON ROWS FROM Sample.Basic由于这些成员名称包含特殊字符,因此必须使用括号。建议使用此处使用的惯例,将所有成员名称括在括号中(即使它们不包含特殊字符)。
-
作为行轴的设置规范,输入“Year(年份)”成员从 Qtr1 到 Qtr4。
SELECT {[100-10],[100-20]} ON COLUMNS, {[Qtr1],[Qtr2],[Qtr3],[Qtr4]} ON ROWS FROM Sample.Basic -
将查询另存为
qry_2ax.txt。 -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
查询的结果应如下所示:
表 28-2 结果:运行双轴查询
| 100-10 | 100-20 | |
|---|---|---|
|
Qtr1 |
5096 |
1359 |
|
Qtr2 |
5892 |
1534 |
|
Qtr3 |
6583 |
1528 |
|
Qtr4 |
5206 |
1287 |
练习 4:查询单个轴上的多个维
要在单个轴上查询多个维:
-
打开
qry_blank_2ax.txt,这是您在上一个练习中创建的查询模板。 -
在列轴上,指定两个元组,每个元组是成员组合而不是单个成员。将每个元组括在括号中,因为每个元组中都有多个成员。
SELECT {([100-10],[East]), ([100-20],[East])} ON COLUMNS, {} ON ROWS FROM Sample.Basic -
在行轴上,指定四个由两个成员组成的元组,使用利润嵌套每个季度:
SELECT {([100-10],[East]), ([100-20],[East])} ON COLUMNS, { ([Qtr1],[Profit]), ([Qtr2],[Profit]), ([Qtr3],[Profit]), ([Qtr4],[Profit]) } ON ROWS FROM Sample.Basic -
将查询另存为
qry_1ax.txt。 -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
结果应类似于以下内容:
表 28-3 结果:在单个轴上查询多个维


100-10 100-20 

East
East
Qtr1
Profit
2461
212
Qtr2
Profit
2490
303
Qtr3
Profit
3298
312
Qtr4
Profit
2430
287
使用 MDX 函数构建集
通过尝试练习,学习如何使用 MemberRange 和 CrossJoin 函数。
MDX 函数的本介绍侧重于生成集的几个函数。您可以用一个简单的函数表达式来替换这样的枚举,而不是手动将成员或元组输入到 MDX 查询中。MDX 函数可以返回集合以及其他值。
例如,Children 是一个集合函数。它返回输入成员的子成员集。因此,Children(Qtr1) 返回 {Jan, Feb, Mar}。
以下练习可帮助您学习在简单查询中使用 MDX 函数。Essbase 支持的 MDX 函数的完整参考列在 MDX 函数列表中。
练习 5:使用 MemberRange 函数
MemberRange MDX 函数返回包含同一代的两个指定成员以及这两个成员之间的成员范围。其语法如下:
MemberRange (<member1>, <member2>, [,<layertype>])其中,您提供的第一个参数是开始该范围的成员,第二个参数是结束该范围的成员。layertype 参数是可选的。
注意:
MemberRange 的替代语法是在两个成员之间使用冒号,而不是使用函数名:member1 : member2.
要使用 MemberRange 函数,请执行以下操作:
-
打开
qry_blank.txt,即您在构建 MDX 查询模板中创建的查询模板。 -
删除大括号
{},在使用函数返回集时不需要这样做。 -
使用冒号运算符选择 Qtr1 到 Qtr4 的成员范围:
SELECT [Qtr1]:[Qtr4] ON COLUMNS FROM Sample.Basic -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
返回 Qtr1、Qtr2、Qtr3 和 Qtr4。
-
使用 MemberRange 函数选择相同的成员范围,即 Qtr1 到 Qtr4。
SELECT MemberRange([Qtr1],[Qtr4]) ON COLUMNS FROM Sample.Basic -
将查询粘贴到 MaxL 客户端并运行它。
-
将查询另存为
gry_member_range_func.txt。
练习 6:使用 CrossJoin 函数
CrossJoin 函数返回来自不同 Essbase 维的两个集的交叉乘积。其语法如下:
CrossJoin(set,set)此函数将来自不同维度的两个集合作为输入,并创建一个作为它们的交叉乘积的集合。这对于创建对称报表非常有用。
要使用 CrossJoin 函数:
-
打开
qry_blank.txt,即您在构建 MDX 查询模板中创建的查询模板。 -
将列轴上的大括号
{}替换为CrossJoin()。SELECT CrossJoin () ON COLUMNS, {} ON ROWS FROM Sample.Basic -
为将提供给 CrossJoin 函数的两个集合参数添加两个逗号分隔的大括号对作为占位符:
SELECT CrossJoin ({}, {}) ON COLUMNS, {} ON ROWS FROM Sample.Basic -
在第一组中,指定产品成员
[100-10]。在第二组中,指定市场成员[East]、[West]、[South]和[Central]。SELECT CrossJoin ({[100-10]}, {[East],[West],[South],[Central]}) ON COLUMNS, {} ON ROWS FROM Sample.Basic -
在行轴上,使用 CrossJoin 跨包含
Qtr1的集的一组度量成员:SELECT CrossJoin ({[100-10]}, {[East],[West],[South],[Central]}) ON COLUMNS, CrossJoin ( {[Sales],[COGS],[Margin %],[Profit %]}, {[Qtr1]} ) ON ROWS FROM Sample.Basic -
将查询另存为
qry_crossjoin_func.txt。 -
将查询粘贴到 MaxL 客户端并运行它。
在使用 CrossJoin 进行实验时,请注意,参数的顺序会影响输出中的元组顺序。
该查询的结果如下所示:
表 28-4 结果:使用 CrossJoin 函数
| 100-10 | 100-10 | 100-10 | 100-10 | ||
|---|---|---|---|---|---|
|
East |
西部 |
南方 |
中央 |
||
|
销售 |
Qtr1 |
5731 |
3493 |
2296 |
3425 |
|
COGS |
Qtr1 |
1783 |
1428 |
1010 |
1460 |
|
利润百分比 |
Qtr1 |
66.803 |
59.118 |
56.01 |
57.372 |
|
利润百分比 |
Qtr1 |
45.82 |
29.974 |
32.448 |
24.613 |
注意:
如果输入集是基本维及其属性维,请考虑使用 CrossJoinAttribute。
练习 7:使用 Children 函数
子代函数返回一组给定成员的所有子代成员。使用以下语法:
Children (member)注意:
Children 的替代语法是将其用作输入成员的运算符,如下所示:member.Children。在本练习中,我们将使用运算符语法。
要使用 Children 函数在第一个轴规范中引入快捷方式:
-
打开
qry_crossjoin_func.txt,这是您在上一个练习中构建的查询。 -
在列轴规范的第二组中,将
[East],[West],[South],[Central]替换为[Market].Children。SELECT CrossJoin ({[100-10]}, {[Market].Children}) ON COLUMNS, CrossJoin ( {[Sales],[COGS],[Margin %],[Profit %]}, {[Qtr1]} ) ON ROWS FROM Sample.Basic -
将查询另存为
gry_children_func.txt。 -
将查询粘贴到 MaxL 客户端并运行它。
您应该会看到与之前 CrossJoin 练习返回的结果相同的结果。
参考层代和 MDX
某些 MDX 函数基于输入 layer 参数执行设置操作。该层表示 Essbase 维的层代或级别。学习使用成员函数引用集。
在 MDX 中,层的概念是指 Essbase 层次中的层代和级别。
在 Essbase 中,层代编号从维名称的 1 开始计数;层代编号越高,与层次中的叶成员越接近。
级别编号在层次结构的最叶部分以 0 开头,最高级别编号是维名称。
您可以通过以下方式指定层参数:
-
生成或级别名称;例如
States或Regions。 -
维名称以及层代或层名称;例如
Market.Regions和[Market].[States]。 -
“级别”函数将维和级别编号作为输入。例如,
[Year].Levels(0)。 -
将成员作为输入的 Level 函数。例如,
[Qtr1].Level返回 Sample.Basic 中的季度级别,即 Market 维的级别 1。 -
Generations 函数使用维和层代编号作为输入。例如,
[Year].Generations(3)。 -
将成员作为输入的生成函数。例如,
[Qtr1].Generation返回 Sample.Basic 中季度的生成,这是 Market 维的第 2 代。
注意:
在 Sample.Basic 数据库中,Qtr1 和 Qtr4 位于同一层中。这意味着 Qtr1 和 Qtr4 也属于同一代。但是,在具有粗糙层次结构的不同数据库中,Qtr1 和 Qtr4 可能不一定处于同一级别,尽管它们属于同一代。例如,如果 Qtr1 的层次结构向下钻取到周,并且 Qtr4 的层次结构在月后停止,则 Qtr1 的级别高于 Qtr4,但它们仍位于同一层中。
练习 8:使用成员函数
使用“成员”函数可返回指定层代或级别的所有成员。与层参数一起使用时,语法为:
Members (layer)
其中,layer 参数指示要返回的成员的生成或级别。
注意:
成员的其他语法为 layer.Members。
要使用“成员”函数:
-
打开
qry_blank.txt,即您在构建 MDX 查询模板中创建的查询模板。 -
删除大括号
{},在使用函数返回集时不需要这样做。 -
使用“Members(成员)”函数和“Levels(级别)”函数在 Sample.Basic 的 Market 维中选择所有 0 级成员:
SELECT Members(Market.levels(0)) ON COLUMNS FROM Sample.Basic -
将查询另存为
qry_members_func.txt。 -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
结果:返回市场维中的所有状态。
使用切片器轴设置 MDX 查询视点
切片器轴是一种将 MDX 查询限制为仅考虑 Essbase 多维数据集的特定区域的方法。通过尝试示例练习,学习如何在 WHERE 子句中使用切片器。
分片器(如果使用)必须位于 MDX 查询的 WHERE 部分中。此外,根据多维数据集规范(FROM 部分),WHERE 部分必须是查询的最后一个组件:
SELECT {set}
ON axes
FROM cube
WHERE slicer使用切片器轴设置查询的上下文;它通常是所有其他轴的默认上下文。
要仅选择 Sample.Basic 多维数据集中的实际销售额(不包括预算销售额),WHERE 子句可能如下所示:
WHERE ([Actual], [Sales])因为 (Actual,Sales) 是在切片器轴中指定的,所以不需要将其包含在 ON AXIS(n) 集规范中。
注意:
同一维不能出现在其他轴和切片器轴上。要使用自己的维中的条件筛选轴,可以使用子选择。
练习 9:使用切片器轴限制结果
使用切片器轴来限制结果:
-
打开
gry_crossjoin_func.txt,这是您在使用 MDX 函数构建集的练习 6 中构建的查询。 -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
请注意其中一个数据单元格中的结果;例如,请注意第一个元组
([Cola],[East],[Sales],[Qtr1])的值为 5731。 -
添加切片器轴以将返回的数据仅限于预算值。
SELECT CrossJoin ({[100-10]}, {[East],[West],[South],[Central]}) ON COLUMNS, CrossJoin ( {[Sales],[COGS],[Margin %],[Profit %]}, {[Qtr1]} ) ON ROWS FROM Sample.Basic WHERE (Budget) -
将查询粘贴到 MaxL 客户端并运行它。
-
请注意,元组
([Cola],[East],[Sales],[Qtr1])的值现在为 5020。 -
将查询另存为
qry_slicer_axis.txt。
通用 MDX 关系函数
MDX 关系函数根据 Essbase 多维数据集大纲中的分层成员关系返回集或成员。
以下 MDX 关系函数返回集。
以下 MDX 关系函数返回单个成员而非集:
练习 10:尝试文档中的一些关系函数示例
要了解关系函数的工作方式,请执行以下操作:
-
单击上表中某个函数的链接,或单击子项。
-
阅读示例,并将 SELECT 查询复制到剪贴板。
-
将查询粘贴到 MaxL 客户机中,添加一个结束分号,然后运行查询,如第一个练习(在 MDX Sets and Tuples 中)中所述。
用于集运算的 MDX 函数
以下集合函数对输入集合进行操作,而不从多维数据集获取更多信息:
练习 11:使用 Intersect 函数
MDX 交叉函数返回两个输入集的交叉列表,也可以保留重复项。通过查找两个集合中都存在的元组,使用它来比较集合。
要遵循的语法为:
Intersect (set, set [,ALL])-
打开
qry_blank.txt,即您在构建 MDX 查询模板中创建的查询模板。 -
从轴中删除空集大括号
{},并将其替换为Intersect()。在“Intersect”花括号内留一些空间以添加更多代码。例如:SELECT Intersect ( ) ON COLUMNS FROM Sample.Basic -
添加两对逗号分隔的括号,用作将提供给 Intersect 函数的两个集合参数的占位符。例如:
SELECT Intersect ( { }, { } ) ON COLUMNS FROM Sample.Basic -
指定 East 的子项作为第一个集合参数。例如:
SELECT Intersect ( { [East].children }, { } ) ON COLUMNS FROM Sample.Basic -
对于第二个集合参数,指定市场维度中 UDA 为“主要市场”的所有成员。例如:
SELECT Intersect ( { [East].children }, { UDA([Market], "Major Market") } ) ON COLUMNS FROM Sample.Basic -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
将返回 UDA 为“主要市场”的所有东部子代。例如:
New York Massachusetts Florida 8202 6172 5029 -
将查询另存为
qry_intersect_func.txt。
练习 12:使用联合函数
MDX Union 函数联接两个输入集,可以选择保留重复项。使用它可以将两个集合组合到一个集合中。
要遵循的语法为:
Union (set, set [,ALL])-
打开
qry_intersect_func.txt,这是您在上一个练习中构建的查询。 -
将交集替换为联合。
-
将查询另存为
qry_union_func.txt。 -
将查询粘贴到 MaxL 客户端并运行它。
虽然 Intersect 返回只包含具有主要市场官方发展援助的东方儿童的集合,但 Union 返回更大的集合。它包括东方的所有子代,以及拥有主要市场 UDA 的所有市场成员。
(New York) (Massachusetts) (Florida) (Connecticut) (New Hampshire) (East) (California) (Texas) (Central) (Illinois) (Ohio) (Colorado) +---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+--------------- 8202 6712 5029 3093 1125 24161 12964 6425 38262 12577 4384 7227
可重用集和成员:MDX WITH 部分
在 MDX 查询的 WITH 部分中定义成员和集有助于在不影响多维数据集的情况下筛选数据。计算成员是仅存在于查询中的逻辑成员。命名集是仅存在于查询中的逻辑集。尝试一个示例练习。
计算的成员和命名集是查询中的逻辑实体,在查询的整个过程中可以多次使用。计算的成员和命名集可以节省代码行以及执行时间中的时间。MDX 查询开头的可选 WITH 部分用于定义计算成员和/或命名集。
以下查询使用计算成员:
WITH
MEMBER [Measures].[Max Qtr2 Sales] AS
'Max (
{[Year].[Qtr2]},
[Measures].[Sales]
)'
SELECT
{ [Measures].[Max Qtr2 Sales] } on columns,
{ [Product].children } on rows
FROM Sample.Basic以下查询使用命名集:
WITH SET [NewSet]
AS 'CrossJoin([Product].Children, [Market].Children)'
SELECT
Filter([NewSet], NOT IsEmpty([NewSet].CurrentTuple))
ON COLUMNS
FROM Sample.Basic
WHERE
{[Sales]}计算成员
计算成员是查询执行期间存在的假设成员。计算成员启用复杂分析,而无需将物理成员添加到多维数据集大纲中。计算的成员存储对物理成员执行的计算结果。
对计算的成员名称使用以下准则:
-
将计算成员与维关联;例如,要将成员 MyCalc 与度量维关联,请将其命名为
[Measures].[MyCalc]。 -
请勿使用实际成员名称来命名计算成员;例如,请勿命名计算成员
[Measures].[Sales],因为“度量”维中已存在销售。
在使用多个计算成员创建比率或自定义总计时,建议为每个计算成员设置解析顺序。
命名集
可以在查询的 SELECT 部分之前使用 WITH SET 关键字定义命名集合。这样做非常有用,因为在构建查询的 SELECT 部分时,可以按名称引用集合。
例如,指定的集 Best5Prods 标识了 12 月份的一组五大畅销产品:
WITH
SET [Best5Prods]
AS
'Topcount (
[Product].members,
5,
([Measures].[Sales], [Scenario].[Actual], [Year].[Dec])
)'
SELECT [Best5Prods] ON AXIS(0),
{[Year].[Dec]} ON AXIS(1)
FROM Sample.Basic练习 13:创建计算成员
此练习使用 Max 函数,这是用于计算的通用 MDX 函数。它返回在集元组中找到的值的最大值。
要遵循的语法为:
Max (set, numeric_value)-
打开
qry_blank_2ax.txt,这是您在 MDX Query Layout with Axes and Cube Specification 的练习 3 中生成的查询模板。SELECT {} ON COLUMNS, {} ON ROWS FROM Sample.Basic -
在行轴集上,指定 Product 的子项。例如:
SELECT {} ON COLUMNS, {[Product].children} ON ROWS FROM Sample.Basic -
在查询的开头,为计算的成员规范添加占位符。例如:
WITH MEMBER [].[] AS '' SELECT {} ON COLUMNS, {[Product].children} ON ROWS FROM Sample.Basic -
要将计算成员与度量维关联并命名为最大 Qtr2 销售额,请将此信息添加到计算的成员规范中。例如:
WITH MEMBER [Measures].[Max Qtr2 Sales] AS '' SELECT {} ON COLUMNS, {[Product].children} ON ROWS FROM Sample.Basic -
在 AS 关键字之后,在单引号内,为名为 Max Qtr2 Sales 的计算成员定义逻辑。
将 Max 函数与集一起使用以求值 (Qtr2) 作为第一个参数,将求值度量 (Sales) 作为第二个参数。例如:
WITH MEMBER [Measures].[Max Qtr2 Sales] AS ' Max ( {[Year].[Qtr2]}, [Measures].[Sales] )' SELECT {} ON COLUMNS, {[Product].children} ON ROWS FROM Sample.Basic -
计算成员“最大 Qtr2 销售额”在 WITH 部分中定义。要在查询中使用它,请在查询的 SELECT 部分中的一个轴上引用它。例如:
WITH MEMBER [Measures].[Max Qtr2 Sales] AS ' Max ( {[Year].[Qtr2]}, [Measures].[Sales] )' SELECT {[Measures].[Max Qtr2 Sales]} ON COLUMNS, {[Product].children} ON ROWS FROM Sample.Basic -
将查询另存为
gry_calc_member.txt。 -
将查询粘贴到 MaxL 客户机并运行它,如第一个练习(在 MDX Sets and Tuples 中)中所述。
该查询的结果如下所示:
表 28-8 结果:创建计算成员

最大第二季度销售额 100
27187
200
27401
300
25736
400
21355
饮食
26787
注意:
MDX 参考文档中提供了更多示例。请参见 MDX With Section 。
迭代 MDX 函数
迭代 MDX 函数循环访问 Essbase 多维数据集中的数据集,执行您指定用于调整结果的任何搜索条件。请参阅基于布尔值测试筛选数据的示例。
筛选器函数示例
以下查询使用 MDX 筛选器函数返回表达式 IsChild([Market].CurrentMember,[East]) 返回 TRUE 的所有市场维成员。查询将返回 East 的所有子项。
SELECT
Filter([Market].Members,
IsChild([Market].CurrentMember,[East])
)
ON COLUMNS
FROM Sample.BasicMDX 中的 Filter 函数与 Report Writer 中的 RESTRICT 命令相当。
使用 MDX 处理缺少的数据
使用 MDX 查询 Essbase 多维数据集时,可以在轴上使用 NON EMPTY 关键字来隐藏不包含值的单元格。处理缺失值的 MDX 函数包括 Avg、CoalesceEmpty、IsEmpty、NonEmptyCount 和 NonEmptySubset。NONEMPTYMEMBER 和 NONEMPTYTUPLE 属性有助于筛选出大型数据集中的空值。
在轴的集合指定之前包括可选关键字 NON EMPTY 会导致隐藏该轴中将完全包含 #MISSING 值的切片。
下面是 NON EMPTY 的轴规范语法:
<axis_specification> ::=
[NON EMPTY] <set> ON
COLUMNS | ROWS | PAGES | CHAPTERS |
SECTIONS | AXIS (<unsigned_integer>)对于轴上的任何给定元组(例如 (Qtr1, Actual)),分片由将此元组与所有其他轴的所有元组组合而产生的单元组成。如果所有这些单元格值都为 #MISSING,则 NON EMPTY 关键字将消除元组。
例如,如果一行中的某个值不为空,则会返回整个行。在行轴规范的开头包括 NON EMPTY 将从查询返回的集中删除以下行切片:

除了使用 NON EMPTY 隐藏缺少的值外,还可以使用以下 MDX 函数处理 #MISSING 结果:
-
CoalesceEmpty ,用于在数值表达式中搜索非 #MISSING 值
-
IsEmpty ,如果输入数值表达式的值为 #MISSING,则返回 TRUE
-
Avg ,除非使用可选的 IncludeEmpty 标志,否则会省略平均值中的缺失值
NonEmptyCount MDX 函数返回集中求值为非 #Missing 值的元组的计数。对每个元组进行求值并包含在此函数返回的计数中。如果指定了数值表达式,则会在每个元组的上下文中对其进行求值,并返回非 #Missing 值的计数。
仅在聚合存储多维数据集上,NonEmptyCount 函数进行了优化,以便只能通过扫描多维数据集一次来计算所有单元的不同计数。如果不进行此优化,数据库扫描的次数将与不同计数对应的单元格数一样多。当大纲成员公式具有以下语法时,将触发 NonEmptyCount 优化:
NONEMPTYCOUNT(set, measure, exclude_missing)exclude_missing 参数通过提高查询执行不同计数计算的度量的查询的性能来支持对聚合数据库进行 NonEmptyCount 优化。
使用 NONEMPTYMEMBER 和 NONEMPTYTUPLE 优化属性,MDX 可以查询大型成员集或元组,同时跳过对仅包含 #MISSING 数据的非贡献值执行的公式。
-
在计算成员或公式表达式的开头使用单个 NONEMPTYMEMBER 属性子句,以向 Essbase 表明在 nonempty_member_list 中指定的任何成员为空时,公式或计算成员的值为空。
-
在计算成员或公式表达式的开头使用单个 NONEMPTYTUPLE 属性子句,以向 Essbase 表明当 nonempty_member_list 中给定的元组中的单元格值为空时,公式或计算成员的值为空。
给定一个输入集, NonEmptySubset MDX 函数返回该输入集的子集,其中所有元组求值结果均为非空。可以为非空检查指定可选值表达式。此函数可帮助优化基于一组已知非空组合很小的大型集的查询。NonEmptySubset 在存在度量时减小集的大小;例如,您可以为特定单位请求非空子集的后代。
MDX 查询中的变量
您可以在 MDX 中使用预定义的 Essbase 替代变量来引用频繁更改的信息,而无需更改查询。要在 MDX 查询或表达式中引用变量,请输入在变量名称前面添加和符号 (&)。
Essbase 中的替代变量用作定期更改的信息的占位符。您可以在 Essbase 多维数据集、应用程序或全局级别设置替代变量,并为每个变量分配值。您可以随时更改值。您必须至少具有数据库管理者的角色才能设置替代变量。请参阅实施变量以更改信息。
要在 MDX 表达式中使用替代变量,请考虑:
-
替代变量必须可以从要查询的应用程序和多维数据集访问。
-
替代变量包含两个组成部分:名称和值。
-
变量名称可以是字母数字组合,其最大大小在名称和相关对象限制中指定。在 MDX 中使用的替代变量名称中,不要使用空格、标点符号或方括号 ([ ])。
-
在要使用该变量的表达式中点,输入变量名称前面带有 & 符号 (&);例如,其中
CurMonth是服务器上设置的替代变量的名称,在 MDX 表达式中包括&CurMonth。 -
执行检索时, Essbase 会将变量名称替换为替代值,该值由 MDX 表达式使用。
例如,编写表达式时显示变量名称 CurQtr,其前面带有 &:
SELECT
{[&CurQtr]}
ON COLUMNS
FROM Sample.Basic对表达式求值时,会将当前值 (Qtr1) 替换为变量名称,以便有效的运行表达式:
SELECT
{[Qtr1]}
ON COLUMNS
FROM Sample.Basic在 MDX 中查询属性
属性描述 Essbase 数据和元数据的某些特征。通过 MDX,您可以编写查询来检索和分析基于 Essbase 属性的数据,这些属性可以是固有的或定制的。可以在 MDX 查询轴或值表达式中调用属性。
内部属性和定制属性
在 MDX 中,properties 描述了数据和元数据的某些特征。MDX 允许您编写使用属性检索和分析数据的查询。属性可以是内部属性,也可以是定制属性。
内部属性
系统属性是为所有维中的成员定义的。为 Essbase 数据库大纲中的所有成员定义的内部成员属性包括 MEMBER_NAME、MEMBER_ALIAS、LEVEL_NUMBER、GEN_NUMBER、IS_EXPENSE、COMMENTS 和 MEMBER_UNIQUE_NAME。
有关每个属性的说明,请参见 MDX Intrinsic Properties 。
定制属性
Essbase 中的 MDX 支持两种类型的定制属性:属性属性和 UDA 属性。属性属性由大纲中的属性维定义。在 Sample.Basic 数据库中,Pkg Type 属性维描述了 Product 维中成员的打包特征。可以在 MDX 中使用属性名称 [Pkg Type] 查询此信息。
属性属性仅为特定维定义,并且仅为每个维中的特定级别定义。例如,在 Sample.Basic 大纲中,[Ounces] 是仅为 Product 维中的成员定义的属性属性属性,并且此属性仅对 Product 维的 0 级成员具有有效值。其他维(如市场)不存在 [Ounces] 属性。Product 维中非 0 级成员的 [Ounces] 属性为 NULL 值。大纲中的属性属性由该大纲中属性维的名称进行标识。
定制属性还包括 UDA 。例如,[Major Market] 是市场维成员上定义的 UDA 属性。如果为成员定义了 [Major Market] UDA,则返回 TRUE 值,否则返回 FALSE。
另请参见 MDX Custom Properties 。
调用查询轴中的属性
您可以列出每个轴集的维和属性组合。执行查询时,将为指定维中的所有成员计算指定的属性,并将其包括在结果集中。
例如,在列轴上,以下查询返回每个 Market 维成员的 GEN_NUMBER 信息。在行轴上,查询返回每个 Product 维成员的 MEMBER_ALIAS 信息。
SELECT
[Market].Members
DIMENSION PROPERTIES [Market].[GEN_NUMBER] on columns,
Filter ([Product].Members, Sales > 5000)
DIMENSION PROPERTIES [Product].[MEMBER_ALIAS] on rows
FROM Sample.Basic使用轴的 DIMENSION PROPERTIES 部分查询成员属性时,可以使用属性的维名称和名称来标识属性,也可以使用属性名称本身来标识属性。当属性名称由其本身使用时,该属性信息将返回该轴上所有维的所有成员,该维将应用该属性。
在以下查询中,MEMBER_ALIAS 属性在年份和产品维的行轴上求值。
SELECT [Market].Members
DIMENSION PROPERTIES [Market].[GEN_NUMBER] on columns,
CrossJoin([Product].Children, Year.Children)
DIMENSION PROPERTIES [MEMBER_ALIAS] on rows
FROM Sample.Basic调用值表达式中的属性
属性可以在 MDX 查询中的值表达式内使用。例如,您可以基于使用输入集中成员属性的值表达式筛选集。
以下查询返回在罐中包装的所有含咖啡因的产品。
SELECT
Filter([Product].levels(0).members,
[Product].CurrentMember.Caffeinated and
[Product].CurrentMember.[Pkg Type] = "Can")
Dimension Properties
[Caffeinated], [Pkg Type] on columns
FROM Sample.Basic以下查询使用 UDA [Major Market] 根据当前市场是否为主要市场计算 [BudgetedExpenses] 值。
WITH
MEMBER [Measures].[BudgetedExpenses] AS
'IIF([Market].CurrentMember.[Major Market],
[Marketing] * 1.2, [Marketing])'
SELECT {[Measures].[BudgetedExpenses]} ON COLUMNS,
[Market].Members ON ROWS
FROM Sample.Basic
WHERE ([Budget])属性的值类型
Essbase 中 MDX 属性的值可以是数字、布尔值或字符串类型。MEMBER_NAME 和 MEMBER_ALIAS 属性返回字符串值。LEVEL_NUMBER 和 GEN_NUMBER 属性返回数字值。
属性属性根据属性维类型返回数字、布尔值或字符串值。例如,在 Sample.Basic 中,[Ounces] 属性属性是一个数字属性。[Pkg Type] 属性是字符串属性。[Caffeinated] 属性属性是布尔值属性。
Essbase 允许具有日期类型的属性维。日期类型属性在 MDX 中被视为数字属性。在将这些属性值与日期进行比较时,请使用标记函数在比较之前将日期字符串转换为数字。
以下查询返回在 2018 年 3 月 25 日推出的所有产品维成员。由于属性 [Intro Date] 是日期类型,因此在比较日期字符串“03-25-2018”之前,必须使用 TODATE 函数将其转换为数字。
SELECT
Filter ([Product].Members,
[Product].CurrentMember.[Intro Date] =
TODATE("mm-dd-yyyy","03-25-2018"))ON COLUMNS
FROM Sample.Basic在值表达式中使用属性时,必须根据其值类型(字符串、数字或布尔值)正确使用属性。
还可以使用数字范围查询属性维。
以下查询检索小型、中型和大型人口范围的销售数据。
SELECT
{Sales} ON COLUMNS,
{Small, Medium, Large} ON ROWS
FROM Sample.Basic当属性用作值表达式中的属性时,可以使用范围成员来使用 IN 运算符检查成员的属性值是否在给定范围内。
例如,以下查询返回填充范围为“中”的所有“市场”维成员:
SELECT
Filter(
Market.Members, Market.CurrentMember.Population
IN "Medium"
)
ON AXIS(0)
FROM Sample.BasicNULL 属性值
并非所有成员都具有给定属性名称的有效值。例如,MEMBER_ALIAS 属性返回大纲中定义的给定成员的替代名称;但是,并非所有成员都可以定义别名。在这些情况下,对于没有别名的成员,将返回 NULL 值。
在以下查询中,
SELECT
[Year].Members
DIMENSION PROPERTIES [MEMBER_ALIAS]
ON COLUMNS
FROM Sample.Basic“Year(年份)”维中的任何成员都没有为其定义的别名。因此,查询为 Year 维中的成员返回 MEMBER_ALIAS 属性的 NULL 值。
属性属性是为特定维的成员和该维中的特定级别定义的。在 Sample.Basic 数据库中,[Ounces] 属性仅为 Product 维的 0 级成员定义。
因此,如果从 Market 维查询成员的 [Ounces] 属性,如以下查询中所示,将出现语法错误:
SELECT
Filter([Market].members,
[Market].CurrentMember.[Ounces] = 32) ON COLUMNS
FROM Sample.Basic此外,如果查询维的非 0 级成员的 [Ounces] 属性,将获得 NULL 值。
在值表达式中使用属性值时,可以使用函数 IsValid() 检查 NULL 值。以下查询在排除具有 NULL 值的成员之后返回 [Ounces] 属性值为 12 的所有 Product 维成员。
SELECT
Filter([Product].Members,
IsValid([Product].CurrentMember.[Ounces]) AND
[Product].CurrentMember.[Ounces] = 12)
ON COLUMNS
FROM Sample.Basic