SQL MDX 中的汇总等效项
SQL Rollup equivalent in MDX
我有一种情况想要查询多个属性(总共 ~8 个)并包括小计。这就是我想要的结果:
╔═══════╦═════════╦════════╦═════════╗
║ Attr1 ║ Attr2 ║ Attr3 ║ Measure ║
╠═══════╬═════════╬════════╬═════════╣
║ All ║ All ║ All ║ 50% ║
║ Foo ║ All ║ All ║ 25% ║
║ Bar ║ All ║ All ║ 90% ║
║ Foo ║ Anna ║ All ║ 42% ║
║ Foo ║ Brian ║ All ║ 12% ║
║ Bar ║ Charles ║ All ║ 10% ║
║ Bar ║ Dory ║ All ║ 112% ║
║ Foo ║ Anna ║ Box ║ 58% ║
║ Foo ║ Anna ║ Circle ║ 13% ║
║ ... ║ ... ║ ... ║ ... ║
╚═══════╩═════════╩════════╩═════════╝
现在,我几乎可以通过执行以下操作到达那里:
select
{[Measures].[Measure]} on columns,
nonempty({
[Dim1].[Attr1].allmembers *
[Dim2].[Attr2].allmembers *
[Dim3].[Attr3].allmembers
}) on rows
from [Cube]
然而,这当然让我得到了一个包含如下成员的集合:
╔═══════╦═════════╦════════╦═════════╗
║ Attr1 ║ Attr2 ║ Attr3 ║ Measure ║
╠═══════╬═════════╬════════╬═════════╣
║ Foo ║ All ║ Box ║ 25% ║
║ Bar ║ All ║ Circle ║ 90% ║
║ Foo ║ Anna ║ Box ║ 16% ║
║ Bar ║ Charles ║ Circle ║ 78% ║
║ ... ║ ... ║ ... ║ ... ║
╚═══════╩═════════╩════════╩═════════╝
我不想要 - 我可以接受他们,除了 8 个维度会让交叉连接变得有点疯狂(它给了我一个超过 40 亿的集合的错误其中的元组......)。现在,如果我写 SQL 我可以做一些简单的事情,比如:
select
Dim1.Attr1,
Dim2.Attr2,
Dim3.Attr3,
Sum(Measures.Measure) as Measure
group by
Dim1.Attr1,
Dim2.Attr2,
Dim3.Attr3
with rollup
但我找不到在 MDX 中重现它的简单方法。我可以用这样的东西手动构建每个汇总级别:
select
{[Measures].[Measure]} on columns,
nonempty(
{
{[Dim1].[Attr1].[All]} *
{[Dim2].[Attr2].[All]} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[All]} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[Attr2].allmembers} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[Attr2].allmembers} *
{[Dim3].[Attr3].[Attr3].allmembers}
}
) on rows
from [Cube]
但是这已经变得单调乏味了,只有三个维度 - 指定其中的 9 组将是令人讨厌的。那么 - 有没有一种方法可以在 MDX 中简洁地执行此操作,还是我只需要使用长期解决方案?
根据之前的研究,我遇到了很多答案,比如 this one 说使用 WITH MEMBER
语句来创建总行 - 但这对我来说毫无意义,因为它导致我试图用 allmembers
函数避免的相同交叉连接行为。
编辑: 这是代码的最新(净化)版本,包括@Danylo 对 NonEmptyCrossJoin
的建议:
NON EMPTY {
NONEMPTYCROSSJOIN(
{[Dim1].[Attribute].[All]} *
{[Dim2].[Attribute].[All]} *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
NONEMPTYCROSSJOIN(
[Dim1].[Attribute].[Attribute].ALLMEMBERS *
{[Dim2].[Attribute].[All]} *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
NONEMPTYCROSSJOIN(
[Dim1].[Attribute].[Attribute].ALLMEMBERS *
[Dim2].[Attribute].[Attribute].ALLMEMBERS *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
...
}
我看不到使用至少一个交叉连接的方法(尽管将您感兴趣的度量放入 NonEmpty() 函数中 - 请参阅评论 - 可能有助于交叉连接 performance/out-of-memory问题)。
SQL ROLLUP 样式的总计根据 GROUP BY 子句中列的顺序排除了 ALL 和非 ALL 的某些组合。 (在您的示例中,此排除在您的结果集中显示为 ALL 的整齐三角形模式)。 MDX 不会这样做:它并不真正关心交叉连接中集合的顺序。
有一种方法可以让 MDX 知道这个顺序。它有点复杂,但可能比您尝试过的冗长 "handbuilt" 方法更容易(或性能更好):
WITH
MEMBER Measures.DimensionsAllPattern AS
CASE WHEN [Dimension1].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
CASE WHEN [Dimension2].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
CASE WHEN [Dimension3].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
... etc up to dimension 8...
MEMBER AllPatternStrNum AS VBA!Cstr(VBA!CLng(Measures.DimensionsAllPattern))
SELECT
{Measures.DimensionsAllPattern,Measures.AllPatternStrNum} ON 0,
FILTER
(CROSSJOIN
([Dimension1].[Hierarchy].AllMembers,
[Dimension2].[Hierarchy].AllMembers,
.... etc
)
,
(Measures.AllPatternStrNum="0") OR
(Measures.AllPatternStrNum=VBA!String(VBA!Len(Measures.AllPatternStrNum),"1"))
)
ON 1
FROM TheCube
这是做什么的:
对于维度中的每个成员组合,根据指定的维度顺序构建与 All/Non-All 模式对应的字符串。例如,{All,Something,All,Something} 将编码为 1010。
第二个计算成员将此度量值转换为数字,然后再转换回字符串:因此 1010 最终会变成 1010,但 0011 最终会变成 11(去除前导零的简单方法)
然后根据第二个成员过滤交叉连接集。它必须等于 0(根本没有所有值),或者是与其自身长度一样长的 1 字符串。
(请注意,我的示例中没有包含任何 NonEmpty 内容,也没有包含您真正想要看到的度量)。
您可能需要将过滤后的集合包装在 ORDER(set,something,BASC) 中,以使其看起来像您想要的那样。
我最近发表了一篇关于此的文章。为了避免交叉连接内存问题,我建议使用 NonEmptyCrossJoin
函数包装集合。在这里阅读更多:http://blog.soft-prestidigitation.com/the-totals-and-the-nonemptycrossjoin-function.html
加速此类 MDX 的一种方法是不要一步完成。 SQL也是如此。使用子立方体。
CREATE SUBCUBE [CubeName] AS
SELECT {SomeMeasures} ON COLUMNS,
{
CROSSJOIN({Field1.ALLMEMBERS},
{Field2.ALLMEMBERS},
More as needed
) }
ON ROWS
FROM [CubeName]
相当奇怪,SubCube 应该与您正在使用的 cube/perspective 同名。
您可以根据需要创建任意数量的子多维数据集,所有子多维数据集都具有相同的名称,然后从缩小的多维数据集中执行最终的 SELECT 语句。
之后放下子立方体。
我有一种情况想要查询多个属性(总共 ~8 个)并包括小计。这就是我想要的结果:
╔═══════╦═════════╦════════╦═════════╗
║ Attr1 ║ Attr2 ║ Attr3 ║ Measure ║
╠═══════╬═════════╬════════╬═════════╣
║ All ║ All ║ All ║ 50% ║
║ Foo ║ All ║ All ║ 25% ║
║ Bar ║ All ║ All ║ 90% ║
║ Foo ║ Anna ║ All ║ 42% ║
║ Foo ║ Brian ║ All ║ 12% ║
║ Bar ║ Charles ║ All ║ 10% ║
║ Bar ║ Dory ║ All ║ 112% ║
║ Foo ║ Anna ║ Box ║ 58% ║
║ Foo ║ Anna ║ Circle ║ 13% ║
║ ... ║ ... ║ ... ║ ... ║
╚═══════╩═════════╩════════╩═════════╝
现在,我几乎可以通过执行以下操作到达那里:
select
{[Measures].[Measure]} on columns,
nonempty({
[Dim1].[Attr1].allmembers *
[Dim2].[Attr2].allmembers *
[Dim3].[Attr3].allmembers
}) on rows
from [Cube]
然而,这当然让我得到了一个包含如下成员的集合:
╔═══════╦═════════╦════════╦═════════╗
║ Attr1 ║ Attr2 ║ Attr3 ║ Measure ║
╠═══════╬═════════╬════════╬═════════╣
║ Foo ║ All ║ Box ║ 25% ║
║ Bar ║ All ║ Circle ║ 90% ║
║ Foo ║ Anna ║ Box ║ 16% ║
║ Bar ║ Charles ║ Circle ║ 78% ║
║ ... ║ ... ║ ... ║ ... ║
╚═══════╩═════════╩════════╩═════════╝
我不想要 - 我可以接受他们,除了 8 个维度会让交叉连接变得有点疯狂(它给了我一个超过 40 亿的集合的错误其中的元组......)。现在,如果我写 SQL 我可以做一些简单的事情,比如:
select
Dim1.Attr1,
Dim2.Attr2,
Dim3.Attr3,
Sum(Measures.Measure) as Measure
group by
Dim1.Attr1,
Dim2.Attr2,
Dim3.Attr3
with rollup
但我找不到在 MDX 中重现它的简单方法。我可以用这样的东西手动构建每个汇总级别:
select
{[Measures].[Measure]} on columns,
nonempty(
{
{[Dim1].[Attr1].[All]} *
{[Dim2].[Attr2].[All]} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[All]} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[Attr2].allmembers} *
{[Dim3].[Attr3].[All]}
} +
{
{[Dim1].[Attr1].[Attr1].allmembers} *
{[Dim2].[Attr2].[Attr2].allmembers} *
{[Dim3].[Attr3].[Attr3].allmembers}
}
) on rows
from [Cube]
但是这已经变得单调乏味了,只有三个维度 - 指定其中的 9 组将是令人讨厌的。那么 - 有没有一种方法可以在 MDX 中简洁地执行此操作,还是我只需要使用长期解决方案?
根据之前的研究,我遇到了很多答案,比如 this one 说使用 WITH MEMBER
语句来创建总行 - 但这对我来说毫无意义,因为它导致我试图用 allmembers
函数避免的相同交叉连接行为。
编辑: 这是代码的最新(净化)版本,包括@Danylo 对 NonEmptyCrossJoin
的建议:
NON EMPTY {
NONEMPTYCROSSJOIN(
{[Dim1].[Attribute].[All]} *
{[Dim2].[Attribute].[All]} *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
NONEMPTYCROSSJOIN(
[Dim1].[Attribute].[Attribute].ALLMEMBERS *
{[Dim2].[Attribute].[All]} *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
NONEMPTYCROSSJOIN(
[Dim1].[Attribute].[Attribute].ALLMEMBERS *
[Dim2].[Attribute].[Attribute].ALLMEMBERS *
{[Dim3].[Attribute].[All]} *
{[Dim4].[Attribute].[All]} *
{[Dim6].[Attribute].[All]} *
{[Dim7].[Attribute].[All]} *
{[Dim8].[Attribute].[All]} *
{[Dim9].[Attribute].[All]} *
[Dim0].[Attribute].[Attribute].ALLMEMBERS
) +
...
}
我看不到使用至少一个交叉连接的方法(尽管将您感兴趣的度量放入 NonEmpty() 函数中 - 请参阅评论 - 可能有助于交叉连接 performance/out-of-memory问题)。
SQL ROLLUP 样式的总计根据 GROUP BY 子句中列的顺序排除了 ALL 和非 ALL 的某些组合。 (在您的示例中,此排除在您的结果集中显示为 ALL 的整齐三角形模式)。 MDX 不会这样做:它并不真正关心交叉连接中集合的顺序。
有一种方法可以让 MDX 知道这个顺序。它有点复杂,但可能比您尝试过的冗长 "handbuilt" 方法更容易(或性能更好):
WITH
MEMBER Measures.DimensionsAllPattern AS
CASE WHEN [Dimension1].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
CASE WHEN [Dimension2].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
CASE WHEN [Dimension3].[Hierarchy].CurrentMember.Properties("LEVEL_NUMBER")="0" THEN "1" ELSE "0" END +
... etc up to dimension 8...
MEMBER AllPatternStrNum AS VBA!Cstr(VBA!CLng(Measures.DimensionsAllPattern))
SELECT
{Measures.DimensionsAllPattern,Measures.AllPatternStrNum} ON 0,
FILTER
(CROSSJOIN
([Dimension1].[Hierarchy].AllMembers,
[Dimension2].[Hierarchy].AllMembers,
.... etc
)
,
(Measures.AllPatternStrNum="0") OR
(Measures.AllPatternStrNum=VBA!String(VBA!Len(Measures.AllPatternStrNum),"1"))
)
ON 1
FROM TheCube
这是做什么的:
对于维度中的每个成员组合,根据指定的维度顺序构建与 All/Non-All 模式对应的字符串。例如,{All,Something,All,Something} 将编码为 1010。
第二个计算成员将此度量值转换为数字,然后再转换回字符串:因此 1010 最终会变成 1010,但 0011 最终会变成 11(去除前导零的简单方法)
然后根据第二个成员过滤交叉连接集。它必须等于 0(根本没有所有值),或者是与其自身长度一样长的 1 字符串。
(请注意,我的示例中没有包含任何 NonEmpty 内容,也没有包含您真正想要看到的度量)。
您可能需要将过滤后的集合包装在 ORDER(set,something,BASC) 中,以使其看起来像您想要的那样。
我最近发表了一篇关于此的文章。为了避免交叉连接内存问题,我建议使用 NonEmptyCrossJoin
函数包装集合。在这里阅读更多:http://blog.soft-prestidigitation.com/the-totals-and-the-nonemptycrossjoin-function.html
加速此类 MDX 的一种方法是不要一步完成。 SQL也是如此。使用子立方体。
CREATE SUBCUBE [CubeName] AS
SELECT {SomeMeasures} ON COLUMNS,
{
CROSSJOIN({Field1.ALLMEMBERS},
{Field2.ALLMEMBERS},
More as needed
) }
ON ROWS
FROM [CubeName]
相当奇怪,SubCube 应该与您正在使用的 cube/perspective 同名。
您可以根据需要创建任意数量的子多维数据集,所有子多维数据集都具有相同的名称,然后从缩小的多维数据集中执行最终的 SELECT 语句。
之后放下子立方体。