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

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

226
说点什么

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

高老师,请帮忙指点下:
如图,只有一个trans,有5个基础字段。建了度量值”涉及数据条数“,是希望只传递切片器的[成交日期],[证券名称]则保留上下文,清除其他所有上下文。
但[成交方向]切片器”全选“或选择”进“时,能按预期取到了所有记录,但选”出“时,未取到全部。帮忙看看是什么原因?谢谢!
涉及数据条数 =
var selectdates=CALCULATETABLE(VALUES(Trans[成交日期]),all(),ALLSELECTED(Trans[成交日期]))
var stocks=CALCULATETABLE(VALUES(Trans[证券名称]))
var qty=CALCULATE(
COUNTROWS(‘Trans’)
,selectdates
,stocks
,REMOVEFILTERS(Trans)
)
return
qty

问题核查-成交方向为出时未取到所有数据.jpg
成员
罗宁

高老师 你好

当筛选器没有参数的时候 calculate是如何工作的
例如:一端表 日期表 链接 多端表销售表

销售员 A 销售区间 2020-12 ~2021-12 销售员 B 销售时间段 2020-1~2121-12
度量值 a = sumx(VALUES(‘日期表1′[月]),if([总销售1]>0,[工作日天数]))
度量值 b = sumx(VALUES(‘日期表1′[年月]),if([总销售1]>0,[工作日天数]))

a度量值 最终结果是迭代了整个日期表,b度量值只迭代了日期表和原始筛选上下文 A 销售员的交集
请问一下这是为什么?

成员
罗宁

高老师好 我的回复发不出去,只能新开一个
这一节课我有很多疑问

1.关于calculate 计算的第一步骤 初始上下文是公式外部环境,包括原始行上下文(如果有的话)和原始筛选上下文。所有显式筛选器参数在这个初始环境中独立计算 》》》此中的 “独立计算” 能否更加具体的说明一下 ,是不是 就是原始上下文作用下的计值表环境中计算筛选器参数

2.为什么第二步会丢弃原始行上下文 而 步骤三 却又 使用列在原始行上下文中的当前值,为正在迭代的所有列提供一个具有唯一值的筛选器 是不是第三步 正式丢弃

3.一旦发生了上下文转换,筛选器参数会在步骤 4 之后应用到筛选上下文中覆盖转换生成的上下文 》》》具体应用于步骤4之后的筛选上下文是如何应用的 ,是不是 就是 作用于同列则覆盖,不同列则合并 。 无论是复制而来的原始筛选上下文还是转换而来的筛选上下文

4. 我尝试描述一下自己对计值流的理解
第一步 在原始的行上下文和筛选上下文环境中,计算calculate筛选器参数
第二步 复制原始筛选上下文
第三步 转换原始行上下文为筛选上下文
第四步 计算调节器
第五步 使用第一步产生的筛选上下文,覆盖 位于同列的原始筛选上下文 以及有原始行上下文衍生的筛选上下文,合并 位于不同列的原始筛选上下文 以及有原始行上下文衍生的筛选上下文

5.下面有两张图 新建列使用的公式 calculate(sum(‘Table1′[Value]),filter(‘Table1’,’Table1′[A]=”a1″)) 和 度量值是一样的
但是最终呈现的结果是不一样的 ,烦请指导一下为什么相同的公式得到的结果不一样 感谢

P2.PNG
p1.PNG
成员
似水无痕

高老师,麻烦再问个问题!
下边的图中,度量值 [销售金额] : 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
)

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

DAX 圣经

导读

初识 DAX

DAX 基础知识

DAX 原理

DAX 高级原理

基础函数类型

迭代函数

CALCULATE 函数

CALCULATE 调节器

基础表函数

条件判断函数

查找匹配函数

时间智能函数

统计类函数

投影函数

分组/连接函数

集合函数

其他函数