代码改变世界

在MDX中使用别名

2009-01-25 19:06  Yin.P  阅读(2338)  评论(0编辑  收藏  举报

  与在SQL查询中一样,在MDX查询中也可以使用别名。通过使用别名可使复杂的MDX查询变得简单,使MDX的结构变得更加清晰,提高MDX查询内的复用性。因为别名中包含的计算只会执行一次,其结果会被缓存,所以在MDX中适当的使用别名可以有效地提高MDX的执行效率。除此之外,在有的场合如果不使用别名甚至会导致MDX查询出错误的结果。

假如我们有个需求要查询门店销售量大于某个值(比如2W)的前提下,其销售额的最大值及最小值和它们之间的差距。对于这个需求,有以下的命名计算定义:

 

MDX别名查询例一
WITH
MEMBER 
[Measures].[Max] AS 
Max
    Filter( 
        Descendants( 
            
[Store].[Store City].CurrentMember, 
            
[Store].[Store City].[Store City] 
        ), 
        
[Measures].[Unit Sales] > 20000 
    ), 
    
[Measures].[Store Sales] 

MEMBER 
[Measures].[Min] AS 
Min
    Filter( 
        Descendants( 
            
[Store].[Store City].CurrentMember, 
            
[Store].[Store City].[Store City] 
        ), 
        
[Measures].[Unit Sales] > 20000 
    ), 
    
[Measures].[Store Sales] 

MEMBER 
[Measures].[DistanceOfMaxMin] AS [Measures].[Max] - [Measures].[Min]

 

    在这个命名计算成员中Filter函数用于筛选出那些销售量大于2W的门店,外层的Min/Max函数用于求出在销售量大于2W的基础上,销售额的最小最大值。在这里Filter函数会重复计算两次,降低了计算效率。其实完全可以利用第一次的筛选结果来进行第二次选择。在这里可以对Filter函数添加一个别名。别名的使用方法与SQL中的别名使用方法类似,不过在MDX中AS关键字是必须的。下面是对上一段代码的修改:

 

MDX别名查询例二
WITH
MEMBER 
[Measures].[Max] AS 
Max
    Filter( 
        Descendants( 
            
[Store].[Store City].CurrentMember, 
            
[Store].[Store City].[Store City] 
        ), 
        
[Measures].[Unit Sales] > 20000 
    ) 
AS [Alias_Filter_Gt2W]
    
[Measures].[Store Sales]

MEMBER 
[Measures].[Min] AS 
Min
    
[Alias_Filter_Gt2W]
    
[Measures].[Store Sales] 

MEMBER 
[Measures].[DistanceOfMaxMin] AS [Measures].[Max] - [Measures].[Min]

 

    在这段代码中通过为筛选方法添加别名[Alias_Filter_Gt2W]复用了先前已经执行的同样一段代码,简化了MDX查询,同时也可以提高MDX的效率。可以用下面的代码来查看结果,图一为查询结果:

MDX别名查询例三
SELECT 

    
[Measures].[Max]
    
[Measures].[Min]
    
[Measures].[DistanceOfMaxMin] 
ON COLUMNS 
FROM [Warehouse and Sales]

 

图一:查询结果

 

    在本文开始的时候提到过在某些时候如果不用别名会影响结果。先来看看下面的代码:

 

MDX别名查询例四
WITH 
MEMBER 
[Measures].[Avg Quantity] AS 
[Measures].[Unit Sales]/[Measures].[Sales Fact 1997 Count]
FORMAT_STRING 
= "###,###,###,##0.00
MEMBER 
[Measures].[Result] AS 
Sum
    Descendants( 
        {
[Time].[Time].CurrentMember} AS [Alias_Reference Time]
        
[Time].[Day] 
    ), 
    iif( 
        
[Measures].[Avg Quantity] < ([Measures].[Avg Quantity][Alias_Reference Time].Item(0)), 
        
1
        
0 
    ) 

SELECT 

    
[Measures].[Avg Quantity]
    
[Measures].[Result] 
ON COLUMNS, 

    
[Product].[Product].Children 
ON ROWS 
FROM [Warehouse and Sales] 
WHERE [Time].[Quarter].[Q4]

 

  这段代码的目的是查询在某个时间段内某产品的平均销售量大于在这个时间段内平均销售量的次数。可以看到这段代码对集合{[Time].[Time].CurrentMember}使用了别名。因为在这里有两个中间结果,一个是整个时段的平均销售量,另一个是某个产品在同一个时间段内的平均销售量。这两个结果都引用同一个时间段,所以要对{[Time].[Time].CurrentMember}添加别名使得两个中间结果可以利用同一个时间段引用。否则可能会得到不正确的结果,而且在这种情况下得到的错误结果很不容易发现,因为得到的结果只有部分是错误的,其它的都是对的。因为在MDX执行的时候,对[Time].[Time].CurrentMember的遍历有一定的机率会使两个中间数据的计算得到同一个时间段引用。因此只有使用别名才是最可靠的手段。

  MDX中的别名可以为查询代码的编写带来很多好处,如对计算的复用、代码结构的整理等,甚至有些查询要求还必须使用它,所以学会合理使用MDX别名有非常重要的意义。

The English edition of this article