加入 PowerBI自己学 知识星球:下载源文件,边学边练;遇到问题,提问交流,有问必答。
以按客户求和的计算列为例,渐进式地认识行上下文嵌套与EARLIER。
新建计算列,默认启用行上下文,公式列=[列名]中的[列名]调用的是这一列在当前行的值。
如果计算列需要调用当前表当前行以外的数据,默认启用行上下文,行对表没有筛选作用,因此,按客户求和的数量总计 = SUMX('订单表', [数量]),返回的会是整表的和,没有达到目的。
自然而然的,要对表进行筛选,筛选表中的客户列与当前行值相同,就会写一个数量总计2 = SUMX(FILTER('订单表',[客户]=[客户]), [数量]),[客户]=[客户]这是个恒等式,返回的还是整表的和,仍然没有达到目的。
解决方案
可以这样理解,我们调用了当前表,但运作机制中会有两个表,当前表为A表,调用表为B表,筛选客户列与当前行值相同,应该筛选B表,条件为B表[列名]=A表[列名],如果只写[客户]=[客户],这两个列都会被认为是B表的列,因为Filter函数中启用的是B表的行上下文。DAX并没有给两个表区分名称,B表中Filter有它的行上下文,A表中的计算列也有它的行上下文,行上下文发生了嵌套,列名是一样的,计算机就会混淆分不清楚。
对于行上下文嵌套的场景,DAX引入了EARLIER函数,EARLIER(表名[列名], 1)理解为外面1层表的行上下文的值,1可以省略。当需要外面两层或N层的行上下文的值时,参数的1改为2或N,当然嵌套2层及以上的情况很少见。EARLIER的恰当理解为外面N层的表的行上下文的值,当外面只有1层的时候,外面1层的表就是当前表,可以粗略地理解为当前行的值。
按客户求和的计算列使用EARLIER函数书写如下,就能达到目的。
数量总计3 = SUMX(FILTER('订单表',[客户]=EARLIER('订单表'[客户])), [数量])
拓展
1 同表调用导致了行上下文嵌套,才会使用EARLIER函数;不同表之间因为表名不同,即便列同名,代码中也有表名做前缀来区分,不存在行上下文嵌套,因此不需要使用EARLIER。
2 VAR是EARLIER的替代选择,性能更高,推荐使用VAR;如果当表比较小,忽略性能,考虑书写便捷,可以使用EARLIER。