深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器

        前言:阅读本文需要有一定的 DAX 基础,因为有很多比较常规的概念没有展开解释,例如ALLSELECTED 以及其他函数的语法结构和概念,这里仅对 ALLSELECTED 作用过程进行描述。

        最近在学习DAX函数,结合《权威指南》还有 Articles - SQLBI 的一些指导文章,感觉很多场景的运用都能够大概理解,但唯独有一个函数 ALLSELECTED 让我感觉实在捉摸不透。书上和论坛上也对这个函数进行了不同方面的讲解,看了之后,自我感觉应该能够很好地理解这个函数,直到有一天想解释一个比较有意思的问题(图1-1),虽然书上也有一个类似案例(图1-2),当时看书的时候没觉得这个案例有什么问题,就觉得差不多大概能理解,所以也没有多想,而且书上也是简略地带过,更多地只是为了展示这种用法。所以也没有给予过多的关注,但是实际想去解释这个问题的时候,不管怎样尝试都无从下手,所以又在网上找了很多文章,感觉都没有在这方面也没有更详细的讲解,网上的文章更多地是在不同的业务场景如何使用 ALLSELECTED 函数,实在也不是我想要的,所以只能花了一点时间结合案例,在Power BI 进行模拟,然后进一步的理解,以求能够理清这个问题的计算过程。写这篇文章只是为了总结自己的理解,同时也希望能够给读者一些启发,在这里补充说明一下,这些结论仅是我自己的个人理解,不能代表实际引擎就是按照这样的方式去计算,不用于实际业务场景使用方法的指导,如果有误,也希望各位指出,以纠正我的理解。

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第1张图片

图 1-1 一个想解释却又怎样都解释不了的问题

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第2张图片

图 1-2 权威指南上类似的案例

------------------------------------------------------分割线------------------------------------------------------------------

        如图 1-2 所示,有两个问题:

  1. ALLSELECTED 激活影子筛选器的结果是什么?
  2. 影子筛选器的存在形式是什么?

        而这两个问题恰恰就是权威指南上以及论坛上都没有涉及的范围,权威指南上也仅是不断地阐述 ALLSELECTED 的复杂性,也在不同的场景去解释这个函数,以及如何更好地使用这个函数。但以上两个问题始终都没有找到答案,所以也造就了我的疑惑,本着钻牛角尖的态度去尝试,所以在Power BI进行模拟,如果有问题各位也可以指出。

-------------------------------------------------以下内容有做更新--------------------------------------------------------

        提前抛出我的结论: ALLSELECTED 作用机制如下

  1. 激活影子筛选器的结果:可以理解为在生成影子筛选器的迭代器之后,对 ALLSELECTED 作用域内的表达式的最外层嵌套一个以影子筛选器作为筛选器参数以及移除参数列的筛选器的ALL CALCULATE。(CALCULATETABLE 同理)。然后再根据结果表达式中的筛选器参数进行交互。实际 FE引擎在内部计算的时候会不会这样嵌套转换我不确定,但是计算效果应该可以按照这样理解。
  2. 影子筛选器的存在形式:与被激活参数列的影子筛选器对应的一组带有数据沿袭的值列表。
  3. 不管是作为表函数还是调节器,都激活 ALLSELECTED 参数范围内可激活的最后一个影子筛选器,作为无参数的调节器时激活所有列可激活的最后一个影子筛选器。
  4. 作为表函数时,在表达式对应的位置,移除所有列的筛选器,将影子筛选器添加到表达式中,参数为列时返回去重后的值列表,参数为表时返回不去重后的表。
  5. 作为调节器时,在表达式对应的位置,移除 ALLSELECTED 参数范围内列的筛选器,同时将影子筛选器添加到表达式中。
  6. 在 PBI 中 DAX 查询都使用的顶级迭代器是 SUMMARIZECOLUMNS ,而这个迭代器使用的影子筛选器与常规迭代器如 ADDCOLUMNS 使用的影子筛选器又不一样。
    1. SUMMARIZECOLUMNS 只有出现在其筛选器参数的列,才会有对应的影子筛选器。就算是迭代的分组列,如果没有出现在筛选器参数中,也不存在对应影子筛选器,分组列也不存在对应的行上下文。
    2. SUMX、ADDCOLUMNS 等迭代器则只要是迭代的列或迭代之前通过 CALCULATETABLE 应用的筛选器,就有对应的影子筛选器。

以下是在 Power BI 对计算过程进行模拟:

1 模拟数据源:

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第3张图片

2 度量值定义

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第4张图片

3 切片器选择

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第5张图片

4 计算结果

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第6张图片

5 分析计算过程

        一般而言,影子筛选器由迭代器生成并使用。在本案例中的迭代器由引擎用于生成矩阵的 DAX 查询中所使用的顶级迭代器 SUMMARIZECOLUMNS 。经过测试, SUMMARIZECOLUMNS 所形成影子筛选器的条件与一般的迭代器不同,分组列也是没有对应的行上下文,SUMMARIZECOLUMNS 的形成影子筛选器必须出现在其筛选器参数中。本案例 SUMMARIZECOLUMNS 筛选器参数包含'销售记录'[地区],所以影子筛选器等价于筛选器参数的选择的列值 '销售记录'[地区] IN { "东北", "中部", "华北" }。

        度量值 [ ALLSELECTED 销售总额 ] 中引入新的迭代器函数 SUMX ,而 SUMX 也会对第一参数 KEEPFILTERSALL( '销售记录'[地区] ) ) 进行迭代,SUMX 形成影子筛选器的过程与SUMMARIZECOLUMNS 不同,迭代参数就可以形成影子筛选器。但是最终恢复的影子筛选器却不仅仅是 ALL( '销售记录'[地区] ),既然影子筛选器的恢复可以理解为嵌套 CALCULATE 并将影子筛选器作为其筛选器参数,所以最终效果会覆盖激活当时外部的同列筛选器,但是这里 KEEPFILTERS 会生效 ,在这里恢复的影子筛选器  KEEPFILTERS ( '销售记录'[地区] IN { "东北", "中部", "华北", "外国", "西北" } ) ,与相对外部现有来自于 SUMMARIZECOLUMNS 筛选器参数的筛选器 '销售记录'[地区] IN { "东北", "中部", "华北" } 进行交互,结果为 '销售记录'[地区] IN { "东北", "中部", "华北" },而不是直接恢复 '销售记录'[地区] IN { "东北", "中部", "华北", "外国", "西北" } 见图 1-3。

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第7张图片

图 1-3 激活的影子筛选器会覆盖当时筛选上下文,但是这里 KEEPFILTERS 生效

         度量值 [ 销售总额 外国 ]中没有引入新的迭代器,所以影子筛选器仍是 '销售记录'[地区] IN { "东北", "中部", "华北" },定义这个度量值主要是为了说明, ALLSELECTED 复杂的地方在于找出影子筛选器实际发生作用的位置以及范围,因为激活后的影子筛选器会进一步与现有的筛选器参数进行交互,形成 CALCUALTE 的新筛选上下文。

        以下是我原来对 ALLSELECTED 作为调节器时不具有移除筛选器的能力的一些看法,但实际引擎可不是这样计算的,算是一个对我理解的一个纠正(尽管这样的理解对结果没有问题),见图 1-4:

      本来我以为 ALLSELECTED 不具有移除筛选器的能力,只是激活影子筛选器,并添加影子筛选器到额外嵌套的 CALCULATE 作为筛选器参数。但是实际上作为 CALCULCATE 的调节器会有两项操作,一在对应为位置处,移除参数列的筛选器,同时激活影子筛选器并使其生效,这两项操作是同时进行的。在图1-4中没有来自于外部的筛选器,所以SUMMARIZECOLUMNS 自然不会有对应的筛选器参数,继而也就没有对应的影子筛选器,所以对于 [ ALLSELECTEDIsAddFilters ] 中作为调节器的 ALLSELECT( '销售记录'[地区] ) 执行移除操作,移除来自于矩阵行标签的 '销售记录'[地区] 的筛选器,也因为 '销售记录'[地区] 没有对应影子筛选器,所以不会有添加影子筛选器的操作,最终的结果返回就是 FALSE。作为对比的 [ AddFilters ],ALLSELECT( '销售记录'[地区] ) 作为表函数,因为 '销售记录'[地区] 没有对应的影子筛选器,作为表函数会忽略除了参数列以外其他列的筛选器返回对应的表,这里对于 '销售记录'[地区] 会返回列 '销售记录'[地区] 筛选器为空时的结果,即去重后的所有列值。做这个对比主要是为了纠正我原来对于 ALLSELECTED 行为的一些看法,如果将 ISFILTERED( '销售记录'[地区] ) 替换成CONCATENATEX( VALUES( '销售记录'[地区] ), '销售记录'[地区] , "," ) 就会发现在这个场景下,无论是 [ ALLSELECTEDIsAddFilters ] 还是 [ AddFilters ] 都会返回连接所有列值的结果,但是ALLSELECTED 作为调节器的时候,执行的是移除筛选器,而非添加全部筛选器的操作。

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第8张图片

图 1-4  ALLSELECTED 移除筛选器

        最后,就是 ALLSELECTED 不管是作为表函数还是调节器,都会激活最后一个影子筛选器,不同的是作为调节器时会多了一项操作就是移除参数列的筛选器,相同的是在激活影子筛选器的时候,都相当于在激活的位置处,嵌套 CALCULATE 并以影子筛选器作为其筛选器参数,并与后续的筛选器参数进一步交互,最终得到新筛选上下文。以下将补充权威指南上对应案例的改写图1-5。

深入理解 Power BI DAX 中 ALLSELECTED 的影子筛选器_第9张图片

 

 图1-5 权威指南上对应案例的改写

你可能感兴趣的:(大数据)