DAX 第六篇:上下文转换
关于计算上下文的规则:
- 筛选上下文用于筛选数据。
- 行上下文用于迭代。
注意:行上下文不用于筛选,也就是说行上下文对应的筛选上下文为空,而CALCULATE函数可以把行上下文转换为筛选上下文。
一,CALCULATE函数根据行上下文创建筛选上下文
CALCULATE函数的强大之处:根据行上下文创建筛选上下文。
如果在行上下文中执行CALCULATE函数,对每一次迭代,CALCULATE函数都会把外部的行上下文转换为等价的筛选上下文,换句话说,把当前行的所有字段作为CALCULATE函数的过滤器参数,以此创建新的筛选上下文。CALCULATE函数的内部不存在外部行上下文,只有筛选上下文,也就是说,CALCULATE函数把外部的行上下文隐式转换为外部筛选上下文(等价于隐式设置过滤器参数),CALCULATE函数再根据外部的筛选上下文和过滤器参数创建自己的内部筛选上下文。
下面两个度量的结果是等价的,由于第一个表达式执行了上下文转换,性能低于第二个:
Sales Amount = SUMX ( Sales, CALCULATE( SUM(Sales[Quantity]) ) ) Sales Amount = SUMX ( Sales, Sales[Quantity]) ## DAX引擎自动在Measure外面添加一个CALCULATE函数
注意:如果表中存在完全相同的多行,那么CALCULATE函数基于行上下文创建的筛选上下文是相同的。
二,迭代函数不会把行上下文转化为筛选上下文
在一个行上下文中,迭代函数不会把行上下文转换为筛选上下文,这就是说,对迭代函数来说,行上下文没有筛选上下文。即对于行上下文中的迭代函数来说,筛选上下文为空,不执行任何过滤。
对于计算列,DAX引擎不会添加CALCULATE函数,下面的计算列的工作机制:
- 迭代函数SUMX不会把行上下文转化为过滤上下文,就是说,Sales不会受到行上下文的过滤,在本例中,DAX引擎不对Sales进行过滤,Sales参数是指迭代整个表。
- 字段[Gross Sales Amount]的值是整个Sales表的Quantity字段的和。
- 注意,如果有其他外部的过滤器对Sales表进行过滤的话,比如Slicer等,迭代器会受到外部过滤上下文的影响。只是不会受到行上下文的影响。
Sales[Gross Sales Amount - All] = SUMX ( Sales, Sales[Quantity]) ## DAX引擎不会在计算列外面自动添加CALCULATE函数
要想把计算列中把行上下文转换为过滤器上下文,只需要在计算列中添加CALCULATE函数,这样的话,行上下文就会转换为过滤器上下文,计算的结果当前行对应的Quantity。
Sales[Gross Sales Amount - Row] = CALCULATE(SUMX ( Sales, Sales[Quantity]) )
三,度量中的上下文转换
DAX的一个重要特性:每个被引用的度量(Measure)都被隐式封装在CALCULATE函数中,这种行为对上下文转换至关重要。由于CALCULATE函数的存在,在任何行上下文中引用度量值,都将被执行隐式的上下文转换。
举个例子,在计算列中引用度量值,计算列[Sales Amount2]和[Sales Amount3]实际上是一样的。
Sales Amount = SUMX ( Sales, Sales[Quantity])
Sales[Sales Amount2]= [Sales Amount] Sales[Sales Amount3]= CALCULATE( SUMX ( Sales, Sales[Quantity]) )
但是这种写法涉及到上下文的转换,CALCULATE函数强制把行上下文转换为筛选上下文,代码运行非常低效。
推广到一般情况,DAX中有两个规则,强制把行上下文转换为筛选上下文:
- 在行上下文中调用CALCULATE函数时,行上下文会自动转换为筛选上下文。
- 由于每个被引用的度量值都被隐式封装在CALCULATE函数中,在任何行上下文中引用度量(Measure)时,行上下文会转换为筛选上下文。
例子1,在Measure中引用Measure
在迭代函数中引用度量时,第一个DAX公式,在DAX引擎内部,会被转换为第二个公式。MAXX是迭代行数,CALCULATE函数处于外部的行上下文中,此时,外部的行上下文会被CALCULATE函数转换为外部的筛选上下文,并根据这个外部筛选上下文和过滤器参数创建自己的内部筛选上下文,最终CALCULATE函数根据内部筛选上下文来执行计算。
Max Daily Sales= MAXX(DimDate'Date', [Sales Amout]) Max Daily Sales= MAXX(DimDate'Date' ,CALCULATE(SUMX(Sales, Sales[Quantity]*Sales[Net Price])) )
例子2,在计算列中引用度量(Measure)
在计算列中引用度量(Measure),DAX引擎也会在Measure前面添加一个CALCULATE函数,把行上下文自动转换为等价的筛选上下文:
Measure_Sum_Quantity = SUMX ( Sales, Sales[Quantity])
Sales[Gross Sales Amount - Row] = [Measure_Sum_Quantity]
下面的结论很关键:不管是在Measure中还是在计算列中,只要引用Measure,DAX引擎都会在Measure前面自动添加CALCULATE函数。因此,计算列中的行上下文会自动转换为等价的筛选上下文。
参考文档: