MDX中的SQL Rollup等效项

时间:2017-01-05 01:21:26

标签: sql-server ssas mdx rollup

我有一种情况,我想查询多个属性(共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
    ) +

    ...

}

3 个答案:

答案 0 :(得分:2)

加速这种类型的MDX的一种方法是不要一步到位。 SQL也是如此。使用子立方体。

CREATE SUBCUBE [CubeName] AS 
 SELECT {SomeMeasures} ON COLUMNS, 
{ 
    CROSSJOIN({Field1.ALLMEMBERS}, 
             {Field2.ALLMEMBERS},
                  More as needed                
                                 ) }
ON ROWS 
FROM [CubeName]

相当古怪,SubCube应该与您正在使用的立方体/透视图具有相同的名称。

您可以根据需要创建任意数量的子多维数据集,它们都具有相同的名称,然后从缩小的多维数据集中执行最终的SELECT语句。

之后放下子立方体。

答案 1 :(得分:1)

我无法看到使用至少一个交叉连接的方法(尽管将您感兴趣的度量放入NonEmpty()函数中 - 请参阅注释 - 可能有助于交叉连接性能/内存不足问题)。

SQL ROLLUP样式的总计根据GROUP BY子句中列的顺序排除ALL和非ALL的某些组合。 (在您的示例中,此排除在结果集中显示为ALL的整齐三角形图案)。 MDX不会这样做:它并不真正关心交叉连接中集合的顺序。

通过让MDX了解此订单,可以做到这一点。它有点复杂,但可能比长期的,#34; 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

这是做什么的:

  1. 对于维度中每个成员组合,根据指定的维度顺序构建与“全部/非全部”模式对应的字符串。例如,{All,Something,All,Something}将被编码为1010。

  2. 第二个计算成员将此度量转换为数字然后返回字符串:因此1010最终将为1010,但0011最终将为11(剥离前导零的简单方法)

  3. 然后根据该第二个成员过滤交叉连接组。它必须等于0(根本没有所有值),或者是一个1s的字符串,只要它自己的长度。

  4. (注意我没有包含我的示例中的任何NonEmpty内容,或者您​​实际想要查看的内容)。

    您可能需要将过滤后的集合包装在ORDER(set,something,BASC)中,以使其看起来像您想要的那样。

答案 2 :(得分:1)

我最近发布了一篇关于此的文章。为了避免交叉连接内存问题,我建议使用NonEmptyCrossJoin函数包装集合。在此处阅读更多内容:http://blog.soft-prestidigitation.com/the-totals-and-the-nonemptycrossjoin-function.html