最近在看calculate函数在计算列中的行为时,碰到了一个让我有点意外的情况。正常来讲的话,calculate无论在计算列还是度量值中都应该遵循相同的计算流程,但是接下来说的这个例子,让我在第一时间对此产生了怀疑,那最后的结论到底是怎样的呢?让我们直接看例子吧
模型中只有一个简单的表格,记录每天不同水果的销量。这里讨论的是calculate函数在计算列中的行为,那我们在这张表建一个新建列sales:

新建列sales, 通过filter条件日期列上加了一个筛选器:2021-1-2
sales =calculate(sum('销量表'[销量]),FILTER(VALUES('销量表'[日期]), '销量表'[日期] = dt"2021-1-2")
在这个计算列中,calculate函数其外部的上下文只有一个行上下文(包括日期,品类,销量),稍后会由calculate函数执行上下文转换,而calculate的显示筛选器参数是在日期列上添加了一个筛选器,按照calculate函数的计算流,calcualte的显示筛选器参数:2021-1-2覆盖由上下文转换形成筛选器,然后再去计算sum函数。(计算列中的上下文转换包含表中的“所有”列,到底是否包含sales列呢?)

以第一行为例:calculate函数的筛选器参数为2021-1-2,而此时,行上下文转换在日期列上形成的筛选器是2021-1-1,显示筛选器参数会覆盖日期列上由行上下文转换形成的筛选器,所以最后在日期列上的筛选器变为:2021-1-2,而此时所有的筛选器变为:2021-1-2, 苹果,196,最后以这个筛选器的组合去筛选表,那么在第一行的计算列中的结果应该是196,按照上述的分析,前四行的计算列的结果都应该是196,但是,但是结果并没有如我们想象的那样??
如果我们将计算列的代码改一下,再添加一个筛选器参数,清除来自计算列上的筛选器。
sales =calculate(sum('销量表'[销量]),FILTER(VALUES('销量表'[日期]), '销量表'[日期] = dt"2021-1-2"), allexcept('销量表','销量表'[品类],'销量表'[日期],'销量表'[销量])

哦,这次的结果符合我们的预期了,比较前后两段DAX,最大的不同是第二段DAX清除来自计算列的筛选器(allexcept函数,除,,,,外都运用ALL函数),所以在多数情况下计算列中由行上下文转换形成的筛选上下文中,不但包含表中已有的列,还会包含你正在新建的新建列。
在这里继续猜测一下,这个新建列在筛选器中到底是个什么样的存在:
1. 如果新建列的初始状态是null的话,那么在计算第一行时,行上下文转换形成的筛选器应当包含: 2021-1-1, 苹果,196,null,由显示筛选器覆盖后,应该变成 2021-1-2, 苹果,196,null,这应该能筛选出第二行记录来,结果并没有,难道是null 不能筛选null ,好比其他计算语言中的null 永远不等null
2. 如果新建列的初始状态是一列Index,这样的话,就不难理解了,因为对于每一行的index不同的话,那么覆盖后的筛选器2021-1-2, 苹果,196,index?中的index没有重复的
3. 可能是DAX在内部注入了特殊的代码吧
我是BISeven,欢迎讨论,欢迎关注





