[MDX学习笔记之三]MDX的上下文(Context)

在前面的Blog中,我们说要构建Cube或编写MDX,就必须理解Cube的结构。可是当熟悉了Cube结构之后,我们还是会有很多困挠。比如:为何有些需求用MDX语句似乎做不出来?为何有些MDX语句无法输出我们想要的结果(不是抱错就是输出结果错误)?为何有些MDX语句执行起来非常的慢?要想解决这些问题,除了了解Cube结构,我们还必须理解MDX的运行机制,而运行机制的首要概念便是上下文(Context)。以下MDX语句可以在SSAS的示例库:Adventure Works中运行。

上下文(Context)
MDX的运行机制可以用一句话来描述——在Cube结构的基础上,按照一定顺序执行MDX中的不同部分,然后根据不同部分的上下文来计算,最后输出。这里有一个问题:何为MDX的上下文呢?上下文是指在所有维度的Hierarchy上都取一个或多个值构成的区域。请看下图:
[MDX学习笔记之三]MDX的上下文(Context)_第1张图片

上图中的蓝色部分好比整个Cube,而红色区域代表了一个上下文。当然实际的Cube包含多个维度,所以实际的样子会比上图(只有两个维度)复杂得多。

这里插一句话,要理解MDX,我们最好忘掉SQL语句。原因在于:1)SQL语句中的上下文一般只有一个,如果多个的话,一般执行速度将会变得很慢。而MDX语句中一般都包含多个上下文,不同的部分上下文往往不同,执行起来速度很快;2)在关系型的二维结构中,SQL语句中的所有的内容都是明确指定的(所有的列和表等),而在MDX语句中,除了明确指定外,很多内容实际是隐含指定的,这些指定在不同语句中可能会给被传递或改写,这就是MDX语句的复杂之处,这也是就是MDX和SQL的最大区别,这同时也是为什么有些需求只能用MDX语句来实现的原因,比如:同比、环比、移动平均、KPI等。

为了加深对上下文的认识,让我们来看一看下面的语句——计算每种产品的平均每天的销售额。

WITH  MEMBER  [ Measures ] . [ Average Internet Sales Amount ]   AS  
AVG (DESCENDANTS( [ Date ] . [ Calendar ] .CurrentMember,  [ Date ] . [ Calendar ] . [ Date ] ,SELF), 
[ Measures ] . [ Internet Sales Amount ] )
SELECT  
{
[ Measures ] . [ Internet Sales Amount ] , [ Measures ] . [ Average Internet Sales Amount ] ON   0 ,
NON EMPTY 
[ Product ] . [ Product Categories ] . [ Product Name ] .Members  ON   1
FROM   [ Adventure Works ]

上面这段MDX语句能够正常的计算出结果,但是,如果我们加上一些限定,比如:计算每种产品在2002年和2003年的平均每天的销售额。
WITH  MEMBER  [ Measures ] . [ Average Internet Sales Amount ]   AS  
AVG (DESCENDANTS( [ Date ] . [ Calendar ] .CurrentMember,  [ Date ] . [ Calendar ] . [ Date ] ,SELF), 
[ Measures ] . [ Internet Sales Amount ] )
SELECT  
{
[ Measures ] . [ Internet Sales Amount ] , [ Measures ] . [ Average Internet Sales Amount ] ON   0 ,
NON EMPTY 
[ Product ] . [ Product Categories ] . [ Product Name ] .Members  ON   1
FROM   [ Adventure Works ]
WHERE
{
[ Date ] . [ Calendar ] . [ Calendar Year ] . & [ 2002 ] [ Date ] . [ Calendar ] . [ Calendar Year ] . & [ 2003 ] }

上面的MDX语句的输出结果中会出现很多#error,其原因在于:在[Measures].[Average Internet Sales Amount]的当前上下文中,由于[Date].[Calendar]仅包含两个成员(即2002年和2003年),所以MDX解析器无法确定哪一个成员是CurrentMember。要想解决这个问题,其中的一个办法是使用Existing,详见下文:
WITH  MEMBER  [ Measures ] . [ Average Internet Sales Amount ]   AS  
AVG (EXISTING  [ Date ] . [ Calendar ] . [ Date ]
[ Measures ] . [ Internet Sales Amount ] )
SELECT  
{
[ Measures ] . [ Internet Sales Amount ] , [ Measures ] . [ Average Internet Sales Amount ] ON   0 ,
NON EMPTY 
[ Product ] . [ Product Categories ] . [ Product Name ] .Members  ON   1
FROM   [ Adventure Works ]
WHERE
{
[ Date ] . [ Calendar ] . [ Calendar Year ] . & [ 2002 ] [ Date ] . [ Calendar ] . [ Calendar Year ] . & [ 2003 ] }


上面的语句中EXISTING [Date].[Calendar].[Date]表示当前上下文中包含的[Date].[Calendar].[Date],所以能够得到正确的结果。

总结
本文简单介绍了MDX的运行机制中的上下文的概念,它是理解MDX的关键概念之一。要深入一些的话 有兴趣的朋友可以看看Mosha Pasumansky的文章:http://www.sqljunkies.com/WebLog/mosha/archive/2006/11/01/slicer_axis_interaction.aspx
http://www.sqljunkies.com/WebLog/mosha/archive/2006/11/12/slicer_axis_interaction_deep_exists.aspx
http://www.mosha.com/msolap/articles/mdxmultiselectcalcs.htm

你可能感兴趣的:([MDX学习笔记之三]MDX的上下文(Context))