3、DAX的筛选上下文详解以及CALCULATE的初步应用

tech2025-10-22  3

DAX—快速入门与原理掌握

现有文章:

1、初识DAX—DAX是什么?能干什么?怎么用? 2、DAX的度量值、计算列、查询分别是什么?数据模型又是什么? 3、DAX的筛选上下文详解以及CALCULATE的初步应用 4、DAX的常用迭代函数详解 5、DAX的常用表函数之VALUES与DISTINCT 6、DAX的ALL类函数详解以及影子筛选上下文的介绍—上篇 7、DAX的ALL类函数详解以及影子筛选上下文的介绍—下篇

PowerBI/DAX的计算组功能是什么?怎么用? PowerBI/DAX的计算组之间的优先级设置

【停止更新】该专栏的知识分享已有免费的视频课程分享在B站,欢迎前往观看!


本文目录

DAX—快速入门与原理掌握一、前言二、初步认识筛选上下文2.1 何为筛选上下文?2.2 筛选上下文的示例2.3 小结 三、深入理解筛选上下文3.1 筛选的列级思维3.2 筛选器的共同作用机制3.3 筛选上下文的创建与修改3.3.1 自动匹配3.3.2 示例 四、总结


一、前言

  在之前的文章里,已经介绍了DAX的基础函数、计算列、查询、度量值、数据模型和两个重要的关系函数,并简单介绍了CALCULATE和FILTER两个函数,相信大家如果做了练习后对以上知识都有了一定的了解和掌握,那么也是时候开始讲解DAX的计值环境了。

  需要说明的是:之前讲解的DAX基础函数的概念仅仅只是特指继承至Excel的函数,DAX的基础函数这个概念其实应该是包括CALCULATE、FILTER、VALUES、RELATED等等这些你以为的比较难的函数,真正的基础函数这个概念,主要是为了与一些语法糖函数作区分,例如大部分时间智能函数都是语法糖函数,而我之前所用的基础函数这个概念只是为了方便引导你们入门,到了现在也该纠正你们的思想了。

  研归正传,本篇文章将介绍外部计值环境中的筛选上下文,所谓的计值环境指的就是一个DAX表达式或在表达式内部的函数在进行计算时所能见到的可见数据。在不同的计值环境中,可见数据的数量肯定是不同的,因此即使是同一个DAX表达式,它在不同的计值环境中得出的计算结果也有可能会不同。计值环境我觉得又可分为外部计值环境和内部计值环境,外部计值环境就是与DAX表达式无关的、一开始就存在的环境,内部计值环境则是在DAX表达式内部某个函数开始计算时所处的环境,之所以分为内外两个环境,主要是因为在DAX表达式内部的某些函数是可以修改外部计值环境的,然后表达式的某些部分又必须在未修改的原始环境里计值,也就是外部计值环境里计值,因此将其分为了内外两个环境比较好描述。

  然后,无论是外部计值环境还是内部计值环境,它都是DAX表达式的计值环境,这个计值环境呢,它又可分为筛选上下文和行上下文两种,所谓的上下文其实指的就是环境的意思。上下文这个概念只是开发者定义的东西,并不是有什么特定内涵,只要你喜欢,完全可以把它叫做筛选环境和行环境,但为了与现实接洽并让你能看懂别人的文章,还是称呼为上下文较好。下面开始正式介绍筛选上下文,行上下文在以后的文章讲解。

二、初步认识筛选上下文

2.1 何为筛选上下文?

  筛选上下文就是某个DAX表达式所处的被筛选后的环境,你可能会疑惑:这个环境是被谁筛选了?,是的,在编写DAX表达式之前也是必须先弄懂外部环境被谁筛选了这一个事情,顾名思义,筛选上下文就是被在数据模型中的某些表或列上设置的筛选器筛选后的数据,也就是可见数据。

  一般需要考虑筛选上下文的都是度量值,前文说过,度量值就是从基础数据表中提取数据并进行处理和聚合后能得到标量值的DAX表达式,这个提取数据的过程就是通过筛选上下文来确定哪些数据可见来完成的。

2.2 筛选上下文的示例

  我知道,看完上面这一段话后,你有极大的可能是处于懵逼状态。所以,在这里我会通过举例来继续说明,先来看一个例子,假如我想要看看总的销售数量是多少,那么可以采用如下的度量值:

总销售数量 := SUM( 'T3销售'[T3销售册数] )

结果如图:

  可以看见,我在’T3销售’表里定义了[总销售数量]这个度量值,在PowerPivot的数据表下方的空白单元格处显示的值与在数据透视表里显示的值是一样的,这都达到了我们的需求:想知道总的销售数量是多少

  但是如果我在数据透视表里加上了行字段或者列字段,那么就开始变得有点意思了,如下图:

  我把T0大类K和T1子类K放到了行字段上进行透视,并将在’T3销售’表里定义的[总销售数量]度量值放到了值字段上,按理来说在数据透视表的每一行都应该是得到总的销售数量才对,也就是数据透视表里的总计行显示的251,毕竟我们定义的度量值求的是总的销售数量,问题出现在哪呢?为什么每一行都返回了各自对应大类下子类的总销售数量?【需要注意的是:在这里有个前提,我的PowerPivot是有数据模型的存在的,所以’T0大类’表和’T1子类’表才可以控制’T3销售’表,你可以尝试下断开数据模型里的关系连接看看会发生什么。】

  其实原因就在于DAX表达式在开始计值前所处的计值环境(在这里是筛选上下文环境),在这里,数据透视表的行标签、列标签、页筛选器以及切片器等等,这些东西都是筛选器,它们在表达式还没有开始计值前就已经筛选了整个数据模型,使得数据模型里的可见数据都是被筛选后的数据。也就是说每个单元格中计算的值都有一个由行、列、切片器和筛选器定义的筛选上下文,所有这些筛选条件都共同定义了上下文环境, DAX 在公式计值之前将上下文应用到模型中。

  你可能还是懵逼的,那么再简单点来讲,例如,在上图中的D5单元格,也就是大类为1科技,子类为11机械这一行上的总销售数量,为什么它的值会等于24?,因为数据透视表的行字段有两个,刚刚也说了数据透视表里的行列标签都是筛选器,那么你就相当于设置了两个筛选器,分别是:大类等于1科技,以及子类等于11机械,你所设置这两个筛选器就会筛选整个数据模型,使得模型里的可见数据只有被它们筛选后的数据,然后你再对这些数据进行求和,这些数据就是大类等于1科技且子类等于11机械的销售数据,那么你对这些数据进行求和,得到的肯定就是24了,其他值也是一样的原理。

  下面通过手动筛选来模拟这个行为,然后由于上面的例子通过数据模型的关系连接能够跨表筛选,手动筛选的话有点不太好表达,所以先在’T3销售’表上通过计算列来添加产品所属大类和产品所属子类两个计算列,所用公式如下:

产品所属大类 := RELATED('T0大类'[T0大类K]) 产品所属子类 := RELATED('T1子类'[T1子类K])

  添加完上面的两个计算列后,就用新添加的列将数据透视表里的对应列替换掉,并用链接回表的方式获取T3销售表的数据,操作如下:

  现在我们有了’T3销售’表的数据了,就可以模拟之前说到的大类等于1科技以及子类等于11机械所在行的总销售数量为什么等于24的行为了,我们可以通过高级筛选来进行手动筛选,操作如下图:

  你还可以在数据透视表里双击D5单元格(在我这里是D5单元格,具体看你的数据透视表位置),就可以看到明细数据,无论你有没有用新添加的列去替换都是一样的,你可以将明细数据与自己手动筛选出来的数据进行对比,看看是否存在不同,具体如下图:

2.3 小结

  筛选上下文其实就是外部筛选器经过筛选的共同作用后,使得在数据模型中的可见数据发生改变,变成只有被筛选后的数据,如果没有任何筛选器对数据模型进行筛选,那么数据模型中的可见数据就是全部数据。其中,属于外部筛选器的有:数据透视表的行标签、列标签、页筛选器以及切片器,如果在PowerBI中还要再加上报表的交互,例如:图表联动、层级钻取、页面钻取等。

  总而言之,言而总之,筛选上下文就是经过一组筛选器共同筛选后得到的可见数据,然后度量值或DAX表达式在此基础上进行计值。

三、深入理解筛选上下文

3.1 筛选的列级思维

  相信很多刚开始学习DAX的人还不能从Excel里的思维模式上走出来,在DAX里,数据是按照列来存储的,而不像Excel那样按照单元格来存储,虽然DAX里的表看起来是一张完整的表,但在存储中是按照一列一列来存储的。所以一个列名的引用就代表了一列的数据,在计算列里之所以能取到列对应的每一行的数据,是因为存在行上下文的原因,同样的,筛选也是按照列来进行的,多个列上的筛选器共同决定了一个筛选上下文。

3.2 筛选器的共同作用机制

  要知道,筛选上下文是由多个筛选器(如果有的话)共同决定的,那么这些筛选器之间是怎么工作的呢?有没有什么优先级呢?

  事实上是有的,在外部计值环境中,筛选器通过相交的行为来决定筛选上下文,而在DAX表达式的内部计值环境中则是存在相交和覆盖两种行为,非相同列的筛选器之间是相交,相同列上的筛选器是后面设置的筛选覆盖前面设置的筛选。其中,相交行为产生的是笛卡尔积。

  此外,不仅筛选器之间有相交或覆盖的关系,在一个筛选器内部也是存在且和或的关系,例如:在大类和子类两列上设置一个筛选器,筛选等于1科技的大类或11机械的子类,那么这个筛选器里面就有一个或的关系,类似的,在大类和子类两列上设置一个筛选器,筛选等于1科技的大类且等于11机械的子类,那么这个筛选器里面就有一个且的关系,像这种在内部就存在关系的筛选器一般称为固化筛选器。

  事实上,如果你有使用过Excel的高级筛选功能,那么就很容易接受固化筛选器的概念,一个固化筛选器就相当于你在公式内部就已经定义好了固化筛选器中的列的关系。对于初学者而言,筛选器是不是固化的其实没什么区别,所以就不多介绍了。

3.3 筛选上下文的创建与修改

  理论总是枯燥的,一个文字功底不行的作者表达出来的东西就更加枯燥了,不仅啰嗦还不能让人看懂,因此在这一节,我不讲理论,只讲例子,并将例子中的计值流讲清楚,这样应该对读者更有裨益。

3.3.1 自动匹配

  在讲例子前,先讲一个东西,那就是自动匹配,自动匹配简单来讲就是当你的数据透视表的行字段或列字段里有多个列,且这些列不是来源于同一张表,那么数据透视表显示的总是它们的笛卡尔积。若这些列来自同一张表,那么数据透视表就只有能匹配到的组合的值。具体看下图:

3.3.2 示例

  首先给出本小节用到的度量值:

销售数量 := SUM('T3销售'[T3销售册数]) 科技大类的销售数量 := CALCULATE([销售数量],'T0大类'[T0大类K]="1科技") 教育大类的销售数量 := CALCULATE(CALCULATE([销售数量],'T0大类'[T0大类K]="2教育"),'T0大类'[T0大类K]="1科技")

  将上面三个度量值一起放到数据透视表的值字段中,行字段只有T1子类K,如下图:

1、筛选器的相交行为

  对于[科技大类的销售数量]这个度量值而言,它的外部计值环境只有在T1子类K字段上有筛选器,在数据透视表的不同行,筛选的数值也不同,例如:在F3单元格,筛选的是11机械,在F4单元格,筛选的是12电子,以此类推。

  用F3单元格作详细说明,其他单元格的原理和计值流是一致的。首先,F3单元格有一个外部筛选上下文,那就是T1子类K等于11机械,然后[科技大类的销售数量]度量值的内部又定义了一个筛选器:‘T0大类’[T0大类K]=“1科技”,也就是T0大类K等于1科技,所以总共有两个筛选器,先执行外部筛选器,然后执行内部筛选器。而前面说过了,DAX表达式的内部计值环境中存在相交和覆盖两种行为,非相同列的筛选器之间是相交,相同列上的筛选器是后面设置的筛选覆盖前面设置的筛选。在这里,内部筛选器后面执行,所以能覆盖前面的筛选,但这里的两个筛选器筛选的不是同一列,所以只有相交行为,而没有覆盖行为。

  所以,F3单元格的最终筛选上下文由这两个筛选器通过相交行为共同决定,那就是:大类等于科技且子类等于机械的销售数据。所以F6-F10单元格的数据才为空,因为不存在大类为科技且子类为课内这些数据。

2、筛选器的覆盖行为一

  以G3单元格来说明[教育大类的销售数量]这个度量值的计值过程,首先它有一个外部筛选上下文,那就是T1子类K等于11机械,然后CALCULATE是先计算筛选器再计算计算器的。它在内部定义了一个筛选器:‘T0大类’[T0大类K]=“1科技”,也就是T0大类K等于1科技,所以总共有两个筛选器,先执行外部筛选器,然后执行内部筛选器,这里的两个筛选器筛选的不是同一列,所以只有相交行为,而没有覆盖行为。所以,G3单元格的最终筛选上下文由这两个筛选器通过相交行为共同决定,那就是:大类等于科技且子类等于机械。

  然后CALCULATE在大类等于科技且子类等于机械的销售数据的筛选上下文里执行第一参数的计算器:CALCULATE([销售数量],‘T0大类’[T0大类K]=“2教育”),是的,这将又一个CALCULATE用在了CALCULATE的第一参数里,是CALCULATE的嵌套。

  将位于第一参数的CALCULATE称呼为第二个CALCULATE,那么对第二个CALCULATE而言,它的外部筛选上下文为:大类等于科技且子类等于机械的销售数据,然后执行内部筛选器:‘T0大类’[T0大类K]=“2教育”,这里共有三个筛选器,一个是子类,另外两个都是大类的筛选器,所以在大类上的两个筛选器发生了覆盖行为,用后执行的筛选器覆盖前面的筛选,也就是用’T0大类’[T0大类K]="2教育"覆盖’T0大类’[T0大类K]=“1科技”,所以,第二个CALCULATE的计算器的计值环境为:大类等于教育且子类等于机械的销售数据,不存在这样的销售数据,所以G3单元格为空。同样的,对于G6单元格而言,第二个CALCULATE的计算器的计值环境为:大类等于教育且子类等于课内的销售数据,存在这样的销售数据所以G6单元格不为空。

3、筛选器的覆盖行为二

  上面介绍了内部筛选器和外部筛选器筛选的列不相同的情况,那么如果在一开始时外部筛选器就和内部筛选器筛选同一列,此时会发生什么?

  为了观察到这种行为,先将数据透视表的行字段改为T0大类K,值字段不变,得到的结果如下图:

  貌似神奇的事情发生了,对于[科技大类的销售数量]这个度量值而言,它的整列都是大类为科技的值,而对于[教育大类的销售数量]这个度量值而言,它的整列都是大类为教育的值。如果你懂了上面的覆盖行为一,那么可以很轻松的理解。无论是[科技大类的销售数量]还是[教育大类的销售数量],它们内部定义的筛选器都和外部筛选器筛选了同一列,那么此时只有覆盖行为而没有相交行为。因此,哪个筛选器最后执行就用哪个筛选器覆盖掉前面的筛选。

  对[科技大类的销售数量]而言,只有一个内部筛选器,所以直接就覆盖掉了外部筛选器,所以整列都是科技大类的销售数量。对[教育大类的销售数量]而言,第一个CALCULATE的内部筛选器覆盖外部筛选器,然后再计算第一参数的计算器,但它第一参数的计算器又是一个CALCULATE,所以第二个CALCULATE的内部筛选器最后执行,所以[教育大类的销售数量]的整列都是教育大类的销售数量。

四、总结

  其实,无论是外部计值环境,还是内部计值环境,都是相对的,就好比上面的[教育大类的销售数量]度量值,对第一个CALCULATE而言,外部计值环境就是数据透视表行标签的筛选上下文,而对第二个CALCULATE而言,外部计值环境就变成了第一个CALCULATE的内部筛选器修改后的上下文。只要理解了筛选器之间什么时候发生相交,又是什么时候发生覆盖,那么筛选上下文你就理解得差不多了。

最新回复(0)