从数据到信息
从信息到洞察

CALCULATE 指南

本文是 CALCULATE 系列的最后一篇,是时候提供关于这个函数全面总结了。之后你在浏览其他文章的时候,很可能会多次回来参考本文的内容,不必担心,这是正常的。每当需要回忆 CALCULATE 的复杂行为时,你都可以在这里找到答案。

不要因为反复查看本文内容而怀疑自己的学习能力,即使一些使用 DAX 多年的开发者,仍然必须提醒自己注意公式的计算规则。DAX 是纯净且强大的语言,但一些容易被遗忘的细节往往能解决特定场景下的关键问题。

CALCULATE 总结

初始环境

CALCULATE计值上下文中执行,该上下文包含一个筛选上下文,可能包含一个或多个行上下文,这是公式计值的初始环境。

创建新的筛选上下文

CALCULATE 创建一个新的筛选上下文,在其中计值第一个参数。新的筛选上下文只包含筛选上下文,由于上下文转换的作用,所有行上下文在筛选上下文中都消失了。

接受三种参数

CALCULATE 表达式接受三种类型的参数:

第一参数必选,将在新筛选上下文中计值的表达式。

显式筛选器参数:用来操作原始筛选上下文,每个筛选器参数都可能使用参数调节器(Modifier),比如 KEEPFILTERS

CALCULATE 调节器:通过删除一些筛选器或更改关系结构,可以修改模型、调整初始筛选上下文的范围。

执行上下文转换

当原始上下文包含一个或多个行上下文时,CALCULATE 执行上下文转换,向上下文堆栈中添加不可见的隐式筛选器。默认情况下这些隐式筛选器会覆盖外部上下文提供的筛选器,而如果提供行上下文的是使用 KEEPFILTERS 的表表达式,这种情况下隐式筛选器的行为也会被 KEEPFILTERS 修改。

CALCULATE 计值流

CALCULATE 遵循一个非常精确的算法来使用所有的参数。当你需要理解某些复杂计算的时候,必须很好地理解这种算法:

  1. CALCULATE 在初始计值上下文环境中的计算所有显式筛选器参数
    初始上下文是公式外部环境,包括原始行上下文(如果有的话)和原始筛选上下文。所有显式筛选器参数在这个初始环境中独立计算,计算完成后,CALCULATE 开始构建新的筛选上下文。
  2. CALCULATE 复制原始筛选上下文,以准备新的筛选上下文
    这个过程中会丢弃原始行上下文,因为新的计值上下文将不包含任何行上下文。
  3. CALCULATE 执行上下文转换
    CALCULATE 使用列在原始行上下文中的当前值,为正在迭代的所有列提供一个具有唯一值的筛选器。值得注意的是此筛选器可能包含也可能不包含单个行,因为上下文转换并不保证新的筛选上下文只包含一行。如果没有正在生效的行上下文,则跳过此步骤。一旦上下文转换创建的所有隐式筛选器都应用于新的筛选上下文,计算就进入步骤 4。
  4. 计算调节器函数 USERELATIONSHIP、CROSSFILTER 和 ALL 类函数
    这个步骤发生在步骤 3 之后。这非常重要,意味着我们可以通过使用 ALL 来消除上下文转换的影响。CALCULATE 调节器在上下文转换之后应用,因此可以更改上下文转换的效果。
  5. CALCULATE 将步骤 1 的结果应用于步骤 4 之后的筛选上下文,得到新的筛选上下文
    一旦发生了上下文转换,筛选器参数会在步骤 4 之后应用到筛选上下文中覆盖转换生成的上下文,也就是 ALL 系列函数移除上下文和模型关系结构更新之后,所以这一步生成的上下文不会被 ALL 影响。同时,筛选器参数的计算发生在原始筛选上下文中,不受同一 CALCULATE 中任何其他调节器或筛选器的影响。如果筛选器参数使用了 KEEPFILTERS,那么该筛选器会被添加到筛选上下文中,而不会覆盖同一列的现有筛选器。

最终,CALCULATE 将步骤 5 生成的筛选上下文应用于模型,计值第一参数。

151
说点什么

1000
 
鼓掌微笑开心憧憬爱你色并不觉得吃瓜doge二哈喵喵思考笑哭捂脸悲伤大哭抓狂汗偷笑打脸捂眼黑线问号晕拜拜闭嘴衰咒骂ok作揖
44 评论数
117 被回复的评论
30 订阅评论的人数
 
查看最近回复
查看最热评论
  订阅本文评论  
最新 最旧 得票最多
提醒
成员
zjhred

老师,有个问题百思不解。 我有一张表 序号 值 A 1 B 3 B 3 C 3 计算列1 = CALCULATE( SUM(‘表'[值]), ‘表'[序号] = “B” ) 得到的结果是 序号 值 计算列1 A 1 NULL B 3… 阅读更多 »

成员
zjhred

一旦发生了上下文转换,筛选器参数会在步骤 4 之后应用到筛选上下文中覆盖转换生成的上下文,也就是 ALL 系列函数移除上下文和模型关系结构更新之后,所以这一步生成的上下文不会被 ALL 影响。同时,筛选器参数的计算发生在原始筛选上下文中,不受同一 CALCULATE 中任何其他调节器或筛选器的影响。

————————–
老师,这段描述能举个实例吗?

成员
Clarlechen

CALCULATE 在初始计值上下文环境中的计算所有显式筛选器参数
初始上下文是公式外部环境,包括原始行上下文(如果有的话)和原始筛选上下文。所有显式筛选器参数在这个初始环境中独立计算,计算完成后,CALCULATE 开始构建新的筛选上下文。

请问老师初始上下文包含外部行列筛选器吗?

成员
做一名学霸

CALCULATE 执行上下文转换
CALCULATE 使用列在原始行上下文中的当前值,为正在迭代的所有列提供一个具有唯一值的筛选器。值得注意的是此筛选器可能包含也可能不包含单个行,因为上下文转换并不保证新的筛选上下文只包含一行。如果没有正在生效的行上下文,则跳过此步骤。一旦上下文转换创建的所有隐式筛选器都应用于新的筛选上下文,计算就进入步骤 4。

老师好,请问隐式筛选器是指啥~~

游客
高壮志

嗯,讲得很详细,很专业,步骤也清楚: 但不明白CALCULATE的计算步骤。

成员
小本本

1.第一个圆圈内多了个的字
2.前四个方框内代表的是同一个新建筛选上下文吗?
3.第一个画线部分, 说的是calculate筛选器参数中的ALL调节器吗?如果是的话,和第二个画线部分描述的”这一步生成的上下文不会被 ALL 影响”不是矛盾了吗?毕竟ALL在第三步已经影响了calculate筛选器参数, 在第四步中也会通过覆盖影响第四步中上下文的生成呀?

calculate计算 (中).jpg
游客
游客

老师好,个人觉得有以下两点需要补充:
1、第3步,上下文转换有可能产生的筛选器与原始筛选上下文有交集,如果在行上下文不加入KEEPFILTERS的情况,应该会替换掉原始筛选上下文(CurDate度量值的上下文转换会覆盖外部的‘DIM_Date[DateKey] = 20220101’)。
2、同1所述,第5步将步骤1计算的筛选器参数应用于步骤4之后,如果筛选器参数所筛选的列与(原始上下文或行上下文转换)得到的筛选内容有交集,那么也会覆盖原始的筛选和上下文转换后的筛选内容(除非加了KEEPFILTERS)。(CurDate2度量值中的‘DIM_Date[DateKey] = 20220102’筛选器参数会覆盖原始上下文和上下文转换所得到的的筛选)
代码:
EVALUATE
CALCULATETABLE (
ADDCOLUMNS (
ALL ( DIM_Date[DateKey] ),
“CurDate”, CALCULATE ( VALUES ( DIM_Date[DateKey] ) ),
“CurDate2”, CALCULATE ( VALUES ( DIM_Date[DateKey] ), DIM_Date[DateKey] = 20220102 )
),
DIM_Date[DateKey] = 20220101
)

以上,不知是否应该加入步骤中说明,使得步骤更加完善,请老师指导!

游客
芒果

高老师,这原文的第五步里面如下:我的问题在下面的括号里。请指点。
CALCULATE applies the explicit filter arguments evaluated at 1. to the new filter context generated after step 4. These filter arguments are applied to the new filter context once the context transition has happened so they can overwrite it, after filter removal — their filter is not(这里是NOT,不明白为什么翻译成被ALL类函数删除?这里是NOT啊。) removed by any ALL* modifier — and after the relationship architecture has been updated.

游客
Hosea

老师,关于计值顺序我有个问题:
如果我使用一个公式: CALCULATE([求和], ALL(‘产品'[颜色])),放在一个矩阵中,矩阵列为’产品'[颜色]。
以矩阵列中 ‘产品'[颜色]=绿色 来看,那么按计值顺序:
1.在初始计值上下文中计算所有的显式筛选参数:
上面的公式中没有显式筛选参数,原始筛选上下文:’产品'[颜色]=绿色,无原始行上下文。
2.复制原始筛选上下文:
‘产品'[颜色]=绿色
3.执行行上下文转换:
无行上下文,不转换
4.计算调节器参数:
第2步中的筛选上下文被ALL(‘产品'[颜色])消除,此时新筛选上下文无筛选。
5.将步骤 1 的结果应用于步骤 4 之后的筛选上下文,得到新的筛选上下文:
第一步中的原始筛选上下文:’产品'[颜色]=绿色,覆盖了第四步中的新筛选上下文。
[求和]在经过 ‘产品'[颜色]=绿色 筛选的数据模型中进行了计算。

以上步骤是我按照计值流推断的步骤,肯定有不对的地方,因为这个公式实际排除了’产品'[颜色]的影响,但是我反复找了好多遍,实在是没找到上述流程具体哪出了问题,请老师解惑。

游客
芒果

高老师:括号里面是我的问题
第一步的这句话: 1.CALCULATE 在初始计值上下文环境中的计算所有显式筛选器参数(这里筛选器指的就是FILTER函数吧?这个筛选器参数指的是筛选器函数作为CAL的参数还是指的FILTER函数的第一参数?比如filter(‘product’,…),这里是不是指的里面的这个’product’参数在初始上下文环境计算?

成员
YUN

1.显式筛选器参数有哪些?
2.既然第5步说,第1步计算得到的筛选器参数会覆盖转换生成的上下文,那转换生成的上下文有什么用?如果说转换生成的上下文可以作为第1步筛选器参数的补充,但前面又提到第1步已经使用过原始的筛选条件,所以所有筛选条件已被第1步吸收,这样看起来第1步就已经把所有筛选条件都吸收了,为何还要分5步?
3.第5步说的覆盖到底是什么关系,并集,交集还是完全重写,如果是完全重写,那上下文转换步骤的作用是什么?

成员
137****4205

感觉这个总结很难理解啊,为什么我在SQLBI上看大师英文讲课或者直接看大师的文章就比较清楚呢

成员
159****3774

老师看下,是不是这样的逻辑?

原始的筛选上下文
转换后的上下文

因为您的CALCULATE 计值流很绕,名词太绕了,看不明白

2.jpg
1.jpg
成员
159****3774

CALCULATE 复制原始筛选上下文,以准备新的筛选上下文
这个过程中会丢弃原始行上下文,因为新的计值上下文将不包含任何行上下文。

问:这一步中会丢弃原始行上下文,是怎样的情况?原始筛选上下文,我理解是一开始在报表页面上的行列维度项,这个丢弃掉为什么?丢弃了不是把原始行上下文也丢弃了吗?

如果老师能画些图就更好理解了。

谢谢

成员
呆萌爱吃鱼

老师请问最后一步是将所有外部筛选上下文和行上下文转换的筛选上下文已经第二参数的筛选上下文进行整合的意思吗

成员
qq936554581

所以在calculate中生成上下文的顺序是:
1 外部筛选器
2 上下文转换
3 ALL
4 第一参数后面的筛选器参数
老师我这么理解对吗?

游客
13910953194

老师,如果既有外部筛选上下文,又发生行下文转换,cal内部筛选参数前有修改器,请问修改器修改发生了几次?我理解行上下文发生转换后,修改器修改了转换后的筛选上下文,这里的转换后的筛选上下文应该是和初始筛选上下文发生了覆盖,同列得话,转换筛选覆盖初始筛选,对吗?
同时,初始筛选文跟内部筛选参数作用,作用前又一次被修改器修改,被修改后再跟筛选参数作用?修改器这里用了2次?

游客
lily

老师,网站何时有新内容?

成员
lily

“这个步骤发生在步骤 3 之后。这非常重要,意味着我们可以通过使用 ALL 来消除上下文转换的影响。”

老师,以上描述不够严谨吧?如果有初始筛选和行上下文转换后的筛选上下文环境并存,all就近调节与all里面的第一参数同列的筛选器,但如果没有行上下文转换发生,all调节的是初始筛选上下文同列吧?

另,既然是 cal的计值流,我认为不应该把 “1.CALCULATE 在初始计值上下文环境中的计算所有显式筛选器参数” 放置在第一步,真正的第一步应该是 “CALCULATE 复制原始筛选上下文,以准备新的筛选上下文”,

还有,第5步:“CALCULATE 将步骤 1 的结果应用于步骤 4 之后生成的新筛选上下文”,应该是在调节器调节后的动作发生后,(调节器调节的可能是初始筛选上下文,也能是行上下文转换后的筛选上下文,如果两个上下文都存在或发生,则优先调节行上下文转换后的筛选上下文,且为同列的筛选器),第5步,应该是:这些筛选上下文和cal 内部的筛选器分别独立计算形成最终的筛选上下文。 您认为呢?

成员
lily

老师,几次翻看了评论,重复实践计值的顺序,您看这次理解是否ok?

总结说来,从外层到内层(从初始->上下文转换->调节器->显示筛选器),内层影响外层。这里影响是指覆盖(替换)、增加或删除或交集或并集。

如果一个度量值既由外部筛选上下文,也有内部筛选器,计算顺序如下:
step1: 外部筛选上下文 先发生复制,就此等待,假设存放在变量var1里;
step2:行上下文遇cal转换筛选上下文,假设存放在变量var2里;
step3: 假设存在all调节器,且all第一参数为一个筛选器,注意,高老师之前评论说过,调节器只调节一次,但这里我不清楚的是就近调节var2? 还是var1?还是调节var2和var1作用后生成的新变量var3上下文? 还是调节var1或var2里有共同列的其中一个变量? 还是仅仅就是调节var2,如果var2里没有相同列,则该调节器不发生作用,等同无此调节器?
step4: step3后生成的调节后的筛选上下文和cal里的显示筛选器,假设3个显示筛选器(这里包括all调节器的第一参数筛选器),分别各自独立发生作用(交集、覆盖或并集等),形成变量var4上下文。
step5:变量var4代表的筛选上下文和var1(外部初筛筛选上下文)相互作用后形成最终的筛选上下文呢?还是 初始筛选上下文var1和行上下文转换的筛选上下文var2,两者共同作用生成另外的筛选上下文,然后被后面的all调节器调节,调节后的筛选上下文和内部的三个筛选器分别独立作用,最后交集生成最终的筛选上下文呢?

老师,麻烦您重点解答下step3和step5,多谢啦。

DAX 圣经

导读

初识 DAX

DAX 基础知识

DAX 原理

DAX 高级原理

基础函数类型

迭代函数

CALCULATE 函数

CALCULATE 调节器

基础表函数

条件判断函数

查找匹配函数

时间智能函数

统计类函数

投影函数

分组/连接函数

集合函数

其他函数