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

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 生成的筛选上下文应用于模型,计值第一参数。

196
说点什么

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

高老师,麻烦再问个问题!
下边的图中,度量值 [销售金额] : SUMX(‘销售表’,’销售表'[数量]*’销售表'[销售单价])
两张图片均是通过公式添加的表!
我的问题是:为什么第1张图和第2张图 公式得到了不一样的结果,图1中CALCULATETABLE函数外部应该没有行上下文(我的理解是,CALCULATE函数已经使任何行上下文无效),因此CALCULATETABLE也不存在行上下文转换为筛选上下文的情况啊,但结果貌似进行了上下文转换,这是什么逻辑?

03.png
02.png
成员
jb870610

高老师,图片中的公式为什么实际上并没有取消地区列的筛选?

1.png
成员
似水无痕

高老师,又得麻烦您一下,对于图2数据透视表的红框单元格计算值来说,图1中的度量值公式其中的CALCULATE函数,有没有原始筛选上下文?
我的理解是:SUMX函数的第一参数,VALUES( ‘产品表'[颜色] ) 在原始筛选上下文下生成了一个单行单列的表,然后CALCULATE函数外部的筛选上下文为 ‘产品表'[颜色] = “Black”。
我理解的计值流顺序是:
1、计算显式筛选器参数: ‘产品表'[颜色] = “Red” ;
2、复制原始筛选上下文:’产品表'[颜色] = “Black”;
3、执行上下文转换:单行单列表转换 ‘产品表'[颜色] = “Black”,覆盖同列原始筛选上下文后的结果仍为 ‘产品表'[颜色] = “Blank”;
4、计算调节器:本例无调节器;因此结果与第3步相同
5、将步骤1的结果应用于步骤4之后的筛选上下文:即 ‘产品表'[颜色] = “Red” 的筛选器覆盖了同列的 ‘产品表'[颜色] = “Black” 的筛选器,因此最终筛选上下文为 ‘产品表'[颜色] = “Red”
6、CALCULATE 将步骤 5 生成的筛选上下文应用于模型,计值第一参数,获得了红色产品的总额;
7、执行SUMX聚合运算。
不知道我的理解是否正确?
麻烦高老师了!
昨天貌似把评论设置为不可见了,重新再发一次!

图片02_14140_2.png
图片01_14140_1.png
成员
竹子

高老师,接楼上的问题麻烦继续问下:
度量值1:= CALCULATE( [Sales Amount] , ALL( ‘Sales’ ) , VALUES( ‘Date'[CalendarYear] ) )
其中显式筛选器参数VALUES为什么在调节器ALL之后啊?

成员
似水无痕

老师,麻烦问下:

度量值1:= CALCULATE( [Sales Amount] , ALL( ‘Sales’ ) , VALUES( ‘Date'[CalendarYear] ) )

其中的筛选器参数:VALUES( ‘Date'[CalendarYear] ) ,是不是就属于计值流第1步中描述的 显式筛选器参数 。

成员
似水无痕

昨天看了些答疑,对图片中的序号为 C 的 新列的结果,计值流我的理解是:

第1步:计算显示筛选器: ‘表'[序号] =”B” ;
第2步:复制原始筛选上下文后的结果:’表'[序号] =”B” ;
第3步:执行上下文转换,将行上下文转换为筛选上下文:’表'[序号] =”C” && ‘表'[值] =3
第4步:计算调节器函数:本例无调节器
第5步:将步骤1的结果应用于步骤4之后的筛选上下文,得到新的筛选上下文:’表'[序号] =”B” 覆盖了同列上下文转换的 ‘表'[序号] =”C” ,因此最终筛选上下文为 ‘表'[序号] =”B” && ‘表'[值] =3 【等同于FILTER(ALL(‘表’) , ‘表'[序号] =”B” && ‘表'[值] =3)】
最终,CALCULATE 将步骤 5 生成的筛选上下文应用于模型,计值第一参数 SUM(‘表'[值]) , 计算数值等于6

我的理解不知道是否正确,麻烦老师给予指正,谢谢老师!

QQ图片20230913090557.png
成员
你猜

高老师,第三步的所有列,值得是原始行上下文的所有列,而不是筛选器参数里面的所有列对吧?
以第二幅图为例:里面有两个迭代,一个是行上下文的迭代,一个是filter内部的迭代。而所有列,指的是Product表的所有列,而不是Product[Color]的所有列。
我的理解正确吧?

代码.png
所有列.png
成员
151****9937

高老师,看了CALCULATE 计值流算法的5个步骤后,有以下问题未想明白,请答疑,谢谢:
1.CALCULATE 外的筛选上下文(如矩阵的行列、切片器等筛选上下文)是在什么时候计算的?这点在5个步骤中均未提及。
2..CALCULATE 外的筛选上下文(如矩阵的行列、切片器等筛选上下文)是如何与CALCULATE 创建的筛选上下文(如显示筛选器参数、上下文转换)合并生效的?这点在5个步骤中也未提及。
3.步骤2 “ CALCULATE 复制原始筛选上下文,以准备新的筛选上下文”,不明白复制的原始筛选上下文有什么用?在什么时候用?
下面是个人对这个问题的猜测,不知是否正确:
复制原始筛选上下文,以准备新的筛选上下文,是不是意味着新的筛选上下文以复制的原始筛选上下文为基础,后续步骤(上下文转换)产生的筛选上下文会跟其进行交互(如覆盖或合并)。
如果上面的理解正确,那么问题1和问题2也就解决了。

4.嵌套的CALCULATE 计值流是不是每层(从外层到内层)都执行上述5个步骤 ?也就是说上面的5个步骤是不是指单层CALCULATE 的计值流?
5.显示筛选器参数是不是最开始被计算,最后被应用?

成员
你猜

老师,显式筛选器参数和隐式筛选器参数的区别,是改筛选器有没有被写出来。
比如calculate中的被写出来的第二参数,都是显式筛选器参数。
例子:Store Sales = CALCULATE([Total Sales], Channel[(channelName)]=”Store”)
里面的Channel[(channelName)]=”Store”就是显示筛选器。
如果calculate中的第二参数未被编写,但是因为行上下文的存在,起到了筛选作用,那么就是存在隐式筛选器,对吧?
例子:Product[SumOfUnitPriceCalc] = CALCULATE ( SUM ( Product[UnitPrice] ) ), 里面虽然没有筛选器,但是形成了筛选作用。所以存在隐式筛选器。
辛苦老师看一下我的理解是否正确?

成员
陈皮糖

老师,我想问一下图片中这个度量值的运算顺序:
1.计算显示的筛选器参数‘Product’[Color] = “Red”
2.复制原始筛选上下文,准备新的筛选上下文
3.执行上下文转换(这里没有)
4.计算调节器all,清除‘Product’[Color] 这一列的筛选——(这里我有疑问keepfilters算作调节器吗)
5.显示筛选器‘Product’[Color] = “Red”应用到新生成的上下文中,keepfilters保持这一列不覆盖同一列上的筛选器
那么这里我的理解是度量值应该只会显示红色的销售额,而不是所有产品的销售额都与红色产品销售额一致。
老师看看哪里出了问题,keepfilters这里我不是很懂,我的理解是执行完all调节器后就执行keepfilters然后最后执行筛选器参数吗?
谢谢老师

calculate.png
成员
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’参数在初始上下文环境计算?

DAX 圣经

导读

初识 DAX

DAX 基础知识

DAX 原理

DAX 高级原理

基础函数类型

迭代函数

CALCULATE 函数

CALCULATE 调节器

基础表函数

条件判断函数

查找匹配函数

时间智能函数

统计类函数

投影函数

分组/连接函数

集合函数

其他函数