Power BI之DAX神功:第3卷第18回 影子筛选上下文ALLSELECTED函数
《DAX神功》第1卷第11回 我只讲了ALLSELECTED函数最基础的功能:计算视觉总计
换成一句话说:无论切片器如何筛选,总计总是显示100%。
但是ALLSELECTED函数太复杂了,它的坑太多了!特别是嵌套问题,还是建议大家去看权威指南和高飞老师的解释。
不同事物针对群体不同,社会上需要让穷人富起来的教程,自然也会有让富人更富有的教程。《九阳神功》和《九阴真经》最大的区别,前者让一个不会武功满身是病的人成为了高手,后者其实创造了更多高手,但是代价也很高。
我个人建议初学者,明智的做法是避开坑,而不是跳到每一个坑里看看有多深!大多情况下建议避开ALLSELECTED函数,除非是最基础的使用。
一、你看不到影子筛选器
影子筛选上下文(影子筛选器),就是筛选上下文,就是一个还没有被激活的筛选上下文。


以下两个度量值,结果一样,但是计算过程可不同
总分1是筛选上下文,总分2的sumx创建行上下文被度量值转换成了筛选上下文
《DAX神功》第3卷第17回 我们了解了,将行上下文转换成筛选上下文对内存消耗大,占用时间长。建议大家,要么使用筛选上下文,要么使用行上下文,尽量避开转换上下文。
【度量值】总分2= sumx('成绩表','成绩表'[分数])
因sumx是迭代函数,生成一个包含成绩表在当前筛选上下文中可见行的影子筛选上下文。
很多书说都是这样介绍的,请问什么是当前筛选上下文中可见行?
答:例如你外部有一个切片器,当你筛选姓名:孙兴华,当前筛选上下文中可见行就是所有包含孙兴华的行。
最重要的一点:如果不使用ALLSELECTED激活影子筛选器时,你看不到它的存在。

你要清楚,迭代函数创建行上下文,行上下文筛选是逐行迭代,他会生成一个行筛选器。
影子筛选器就是复制你的当前筛选上下文的筛选器,生成影子筛选器,等ALLSELECTED函数激活。下面我们通过实例来讲解:
二、当ALLSELECTED函数做筛选调节器
以下两个度量值我们在《DAX神功》第1卷第11回详细讲解过
在没有筛选的情况下:

我筛选张三和李四时:

矩阵就相当于SQL中的一个查询,我们的查询可以生成一张表,因为我们现在还没有讲DAX Studio,但是Access基础篇讲过生成表查询,矩阵是查询它肯定也可以生成一张表,所以我们可以使用新建表来演示:
接下来我们回忆几个知识:
<1> 数据沿袭:详见《DAX神功》第2卷第21回

<2> SUMMARIZECOLUMNS函数 详见《火力全开》笔记23.01

利用我们使用之前学过的知识,将矩阵变成一张表:
我问你第一个问题,切片器来自哪里?是不是来自学生表的姓名列?假设我们选了张三和李四
可以使用表构造函数来表示:{"张三","李四"}
可是你的表构造函数生成的这张表,和我的学生表姓名列有什么关系呢?所以这时我们要应用数据沿袭原理。
TREATAS({"张三","李四"},'学生表'[姓名]) // 将第1参做第2参的筛选器,在学生表姓名列上做标记。

SUMMARIZECOLUMNS第1参数是对哪个列分组:我们需要对'学生表'[姓名]分组
但是,'学生表'[姓名]有3个人,我们外部切片器是不是只选了张三和李四?
现在可以使用SUMMARIZECOLUMNS第2参数去筛选第1参数,我们筛选张三和李四:TREATAS({"张三","李四"},'学生表'[姓名])
最后,配上那3个度量值增加3个列就OK了!
现在看结果和矩阵是一样的:

<3> 我们进入分析状态
无论外部的切片器和被我们转换成TREATAS({"张三","李四"},'学生表'[姓名])都是一个意思,它们都是普通筛选器,有人叫他显式筛选上下文(显式筛选器)。
SUMMARIZECOLUMNS是迭代函数,他是行上下文,逐行迭代。
度量值[总分1]:筛选器怎么筛选,我就怎么变!原理如下:

度量值[all总分]:删除所有筛选器,返回所有人分数总和。
Ps:这里的删除所有筛选器,指的是删除所有筛选器进行计算,得到结果。并不是说不筛选张三和王五!

姓名列的张三和王五,是显式筛选器进行的筛选,但是他们返回的结果,是在同时删除了行上下文筛选器和显式筛选器的情况下进行的计算,也就是所有人的成绩总和。
度量值[allselected总分]:
迭代函数生成一个包含学生表[姓名]的影子筛选器。它不包含整个学生表[姓名]组成的表。只包含其在当前筛选上下文中可见的行。可见行:张三、李四。实际上,影子筛选器在迭代过程中是不活动的,除非它被一个叫做 ALLSELECTED 的函数激活。
ALLSELECTED会在删除行上下文筛选器和显式筛选器的情况下,激活影子筛选器,最终计算张三和李四的总和值。
Ps: ALL函数是删除所有筛选器后进行计算。 ALLSELECTED是删除所有筛选器后激活影子筛选器进行计算。影子筛选器是张三和王五,结果就是:张三+王五

官方解释:ALLSELECTED作为筛选调节器时,将恢复参数所指定列或表的最后一个影子筛选上下文,如果不存在影子筛选上下文则不执行任何操作。
三、当ALLSELECTED函数做表函数
友情提示:正常情况下我们是不会这样做的,强烈建议避开ALLSELECTED函数
【1】参数为列

返回结果:

Calculatetable第1参数是表,这张表由filter生成,筛选出所有人的名字,再通过Calculatetable筛选一班和二班的学生姓名。filter确实创建了影子筛选器:姓名列的张三、李四、王五、小张、小王、小李。但是影子筛选器没有被激活。因为没有使用ALLSELECTED函数
当我们将Values替换成Allselected时:
返回结果:

filter生成的影子筛选器是'Sheet1'[姓名],但ALLSELECTED不可能将筛选器应用到班级列。ALLSELECTED删除了所有筛选器,激活了影子筛选器,但是影子筛选器是姓名列,Calculatetable的筛选器并没有对姓名列进行筛选,所以结果是返回所有人姓名。
注意:VALUES 和 DISTINCT 考虑筛选上下文,而 ALLSELECTED 不考虑。它在单个列上工作,并检查该列是否被影子筛选上下文过滤,忽略任何交叉筛选。
因为我们的案例只有一张表,但是你要记住ALLSELECTED忽略任何交叉筛选,VALUES 和 DISTINCT不忽略交叉筛选。
上面这个案例,ALLSELECTED函数没有找到自己能激活的影子筛选器,所以它在本案例中的作用等于同ALL函数。ALL是删除其它筛选器,ALLSELECTED删除其它筛选器激活影子筛选器。
如果想激活影子筛选器,怎么办?既然知道影子筛选器是'Sheet1'[姓名],你只能去筛选姓名
返回结果:

如果你将ALLSELECTED函数改成ALL函数,ALL删除筛选器,但是不会激活影子筛选器
返回结果:

【2】当参数为表的时候
ALLSELECTED(表):大家都知道一张表由多个列组成,任何一个列都可能通过筛选器筛选,也可以被定义为影子筛选器。不嵌套是真香,一嵌套是真坑!(我不给你们讲嵌套,因为那些都可以避免,我不想坑你们)
返回结果:

filter生成了Sheet1所有列的影子筛选器,ALLSELECTED激活了所有影子筛选器,所以随意筛选了。恰恰因为这样,一张表中可能有10多个列,有显式筛选器,有影子筛选器,东西一多你就乱了。所以事情没有这么简单!切记要小心!尽量避开ALLSELECTED函数。

孙兴华讲PowerBI火力全开》PowerBI必学课程
https://www.bilibili.com/video/BV1qa4y1H7wp
《DAX神功》文字版合集:
https://www.bilibili.com/read/readlist/rl442274
《DAX神功》视频版合集:
https://www.bilibili.com/video/BV1YE411E7p3
PowerBI(DAX函数)、PowerQuery(M函数)、Python办公自动化、Python爬虫、Python数据分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等