加入 PowerBI自己学 知识星球:下载源文件,边学边练;遇到问题,提问交流,有问必答。
上下文,全称计值上下文,英文是Context,也可以翻译成计值环境,指DAX运算时所处的数据前提。上下文分为筛选上下文和行上下文,列运算遵照筛选上下文,行运算遵照行上下文。
了解了上下文,就能知道DAX运算会返回什么样的结果,进而修改上下文,返回需要的结果。
筛选上下文
DAX的度量值默认是基于模型的一个筛选后的子集进行运算的,这个子集是它的数据前提,就是它的筛选上下文。可以理解,度量值的运算是先按照某些指定条件去筛选模型抽取数据,在此基础上进行运算返回结果,这些指定条件就是筛选上下文。筛选上下文可以在筛选器、切片器、其它视觉对象带来的交互筛选、视觉对象的轴、矩阵的行和列、甚至是度量值的公式中实现。
比如对于销量度量值,我们可以通过以下方式给它一个筛选上下文客户=张三。
销量 = SUMX('订单表', [数量])
在客户筛选器中筛选张三,度量值就返回张三的销量。
在客户切片器中筛选张三,度量值就返回张三的销量。
在矩阵中,无论是把客户放在行或者列,行或列中张三这个名字对应的度量值返回的都是张三的销量。
*矩阵的行筛选依然是筛选上下文,虽然在矩阵中叫行,但是此行非彼行,它和行上下文不是一回事。
写一个张三销量的度量值,同样返回的是张三的销量。
张三销量 = CALCULATE([销量], FILTER('客户表',[客户]="张三"))
行上下文
筛选上下文已经理解了,但是在度量值中,筛选上下文的对象是列,实际上它还会对这一列的每一行进行迭代聚合,求和也好,求最大值也好,在筛选后的表内,逐个累加或逐个比大小取最大值,甚至还可能先在每一行做一步运算,再进行迭代,比如先算出一个金额=数量*单价,每一行做的这一步运算,需要用表内的当前行的数据运算,此时,就需要行上下文了。
拿表的计算列举例,计算列默认启用行上下文,行上下文中可以直接引用列做运算,类似Excel的单元格公式。新建列金额可以输入:
金额 = [数量]*[价格]
计算列是可见的物理表便于理解,在度量值中,具备迭代功能的函数同样需要行上下文,比如SUMX、MINX、RANKX、ADDCOLUMNS、FILTER等函数,它们的本质是在其运算过程中,对一个不可见的过程表逐行运算(包括判断)生成每行的结果,再进行迭代聚合运算(FILTER比较特别,它只按条件判断筛选返回一个表,不执行聚合),所以它们的参数表达式也可以直接引用列。新建度量值可以输入金额 = SUMX('订单表', [数量]*[价格]) ,其中的[数量]*[价格],就是用的订单表每一行的上下文,逐行运算出一个结果。
如果没有行上下文的设置,仅靠度量值的筛选上下文,是没办法在表内进行每行运算的。
比如把度量值写成金额 = '订单表' [数量]* '订单表' [价格]),就会报错。因为度量值是在列上做聚合运算,不存在当前行的概念,没有行上下文,所以度量值的表达式不能直接引用列,必须在列的外面套上聚合函数才行。如果度量值直接引用列,会有提示报错信息。
或者把度量值写成金额 = SUMX('订单表', [数量])* SUMX('订单表', [价格]),先求和再相乘,其中价格求和并没有意义,得到的自然不是想要的结果。
拓展
CALCULATE是筛选上下文的开关,每一个度量值都用到了它,只是度量值默认开启筛选上下文省略了CALCULATE,写不写CALCULATE效果相同。但是在计算列或者迭代函数的参数表达式(比如SUMX的第二参数),要不直接用度量值,要不就用套上CALCULATE的表达式,不能省略CALCULATE,否则返回的会是全表每一行都用相同的值相加的结果。