Power BI之DAX神功:第3卷第20回 无参数的ALLSELECTED函数,用1+1等于2的方法避坑
ALLSELECTED 函数支持三种类型的参数:
单列或多列:ALLSELECTED (表名[列名])
整张表:ALLSELECTED (表名)
关于以上两种参数,我们分别在《DAX神功》第1卷第11回、第3卷第18回、第19回做了详解
当然,我讲的并不深入,因为路不只一条,有些困难是要迎面而上,但是有一些是可以避开的。我自己也选择避开!当然我并不反对你深入研究,上节课我也告知你深入研究的地方。
你还可以使用不带参数的 ALLSELECTED(),今天我们重点讲讲不带参数的情况
注意:在不使用任何参数的情况下ALLSELECTED函数只能作为 CALCULATE或CALCULATETABLE 调节器。因为它没参数,它肯定无法返回成一张表,自然也就做不成表函数。
有了上面这句话,问题就简单多了,之所以单拿出来讲,是因为DAX专家很多代码没有必要写成那样,在学习ALLSELECTED()无参数之前,我们需要先理解ALL()无参数。


一、ALL()无参数
【度量值】总分 = SUM('成绩表'[分数])
【度量值】all学生表 = CALCULATE([总分],ALL('学生表')) // 删除学生表所有列的筛选

【度量值】all学生表姓名 = CALCULATE([总分],ALL('学生表'[姓名]))
// 只删除学生表姓名列的筛选
【度量值】all学生表班级 = CALCULATE([总分],ALL('学生表'[班级]))
// 只删除学生表班级列的筛选,但是学生表姓名列可以筛选

【度量值】all成绩表学号列 = CALCULATE([总分],ALL('成绩表'[学号]))
// 删除成绩表学号列的筛选,不影响其它筛选

【度量值】all成绩表 = CALCULATE([总分],ALL('成绩表'))
// 因为学生表与成绩表是一对多关系,成绩表是多端向一端扩展学生表中的所有列,所以当all成绩表时,成绩表的扩展表中所有列都删除筛选。

【度量值】all无参数 = CALCULATE([总分],ALL())
// 在整个模型中删除任何筛选器

因为我们只有两张表,all()返回的结果与all(成绩表)是一样的
为了解释这个问题,我们再手贱一次


《DAX神功》第1卷第2回我们学习了,箭头方向符合条件时,在整条线路中不存在多对多关系时,开始表可以筛选结束表。我们制度两个度量值:
返回结果:

原本学生表中的姓名列是可以筛选日期表,但是当使用all()整个模型中原本能用的筛选器都被删除了。因为学生表和日期表都是一端表,你总不能说在一对多关系中一端表有扩展列吧?
二、ALLSELECTED()无参数
ALLSELECTED():激活任何列最后一个影子筛选器,如果没有影子筛选器当然无法激活了。
通过商品编码,建立一对多关系:

我们将上面两个度量值放入矩阵:

《DAX神功》第3卷第18回 原例,只是改了个表。我跟大家说矩阵就是查询,是查询就能生成表,就可以通过新建表举例:过程就不再重复了,我们直接新建表
返回结果:

显式筛选器:苹果、土豆、西瓜
影子筛选器:商品表[商品名称]通过显式筛选器后显示的可见行
allselected删除所有筛选器,激活影子筛选器后进行计算,所以每一行显示6+4+null=10
现在我们将其改成allselected()无参数
返回结果:

因为我们案例中,只有一个列上有影子筛选器,且只有一个影子筛选器。我跟大家一直说,不建议你们嵌套或在复杂公式中使用allselected函数。切记!如果我们尽量避开allselected函数,换而言之,ALLSELECTED()存在的意义就很小了。
三、计算从未购买过某些产品的客户数量
这是一道由DAX专家举出的例子,如果是我,我会用下面的方法做:
返回结果:

上面的方法,就算是DAX初学者也会吧?这不就避开了Allselected了吗?
allselected一旦使用,连专家也会进入走火入魔的状态,当年欧阳峰前辈第2次华山论剑,虽然胜出,可是身体状况...例如这个案例,DAX专家这样写。(如果你觉得书上不是这样写的,麻烦您问问作者或译者,看是不是有勘误)
度量值如下:
返回结果:

你看上去没毛病吧?你筛选一下商品名称看看

解决方法,将allselected()改成all()
返回结果:

因为filter创建了tb1中所有列的影子上下文,如果使用allselected()他会激活这个影子筛选器,可是我现在的实际情况就不能让它筛选。如果一定要这么写公式,我也是这样写:
返回结果:

这不也避开了allselected吗?当然这样写都没必要,你就用我第一种方法就好了。
四、将销售额计算范围缩小至首年客户

意思:B1和B2第1年就买东西了,要计算首年顾客,在每个年份的消费金额。不需要B3的数据。
制作动态日期表:

我们先看看DAX专家是这样写的:写的对!太对了!
返回结果:

你知道困扰你的地方在哪里吗?因为他使用了ALLSELECTED(),哪有影子呀?
在这里使用ALLSELECTED()和all()是一样,没影子就跟all()一样了
而且tb2根本就不用all(),干嘛呀?先删除筛选再恢复筛选。你看我下面的写法:
返回结果:

公式分析:
(1)FIRSTNONBLANK('日期表'[年],[总销售]) // 第一个销售不为空的年份 ,返回2020
// 这个2020具有'日期表'[年]的数据沿袭,详见《DAX神功》答网友问12
(2)这个2020可是固定的,不能筛选,因为我们确定的是首年永远都是2020年。
CALCULATETABLE(FIRSTNONBLANK('日期表'[年],[总销售]),ALL())
(3)CALCULATETABLE(VALUES('销售表'[会员卡号]),tb1) // 筛选2020年的会员卡号,返回会员卡号是B1、B2的这张表
(4) CALCULATE([总销售],tb2) // 筛选会员卡号是B1和B2的销售
我就问你,这里面有原理吗?这不都是语法吗?
好比,快递就在楼下快递柜里,我下去拿回来就好了!不行,为了研究原理,我一定要去法院起诉,让法院把这个快递判给我,我才能去取。结果是相同的,最终快递都回到我手中了,可是后者有什么必要呢?这快递本来就是我的。
再次建议大家,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等等