Power BI之DAX神功:第2卷第22回 简单筛选器与固化筛选器
一、简单筛选器:列筛选器与表筛选器的区别


【度量值】总数量 = sum('销售表'[销售数量])
【度量值】李四列筛选 = CALCULATE([总数量],'商品表'[供商]="李四")

【度量值】李四表筛选 = CALCULATE([总数量],FILTER('商品表','商品表'[供商]="李四"))

我们使用日期做行筛选时,发现结果是一样的:

但是大家心里都懂,这不一样:《DAX神功》第1卷第18回 我们讲过列筛选器的等价公式:
Ps: 因为现在还没有讲扩展表的知识,所以先以等价公式做解释
李四列筛选 = CALCULATE([总数量],'商品表'[供商]="李四")
李四列等价 = CALCULATE([总数量],FILTER(all('商品表'[供商]),'商品表'[供商]="李四"))
李四表筛选 = CALCULATE([总数量],FILTER('商品表','商品表'[供商]="李四"))
从上面的公式我们可以看出,列筛选与表筛选的区别,列筛选等同于删除了指定列的筛选

二、简单筛选器:两种筛选关系
【1】双人成行(合作)
双人成行很多人都玩过,是一款典型的合作游戏,双人配合游戏,非常好玩!

不一定是两个筛选列,可以是多个。但是大家要协同工作得到最后的答案:
合作 = CALCULATE([总数量],'销售表'[日期]=date(2021,1,1),'商品表'[供商]="李四")
// 在销售表日期列筛选2021/1/1,在商品表供商列筛选李四

【2】二手游戏(套娃)
我们买完一个实体版游戏,通关了,不想玩了,可以卖掉回血。但是二手游戏大多是个人交易,你要承担如下风险:
你买游戏,他寄来的是不是空盒
你买游戏,二手卡带和光盘划伤是否会影响读取
你卖游戏,对方收到会不会到手后砍价
你卖游戏,对方会不会收到后告诉你是空盒
.......风险还有很多不再例举
二手游戏我觉得当面交易,试好付款的方式最靠谱。

所以套娃会有很大的风险,我们尽量避免套娃:
《DAX神功》第1卷第18回:我提到了Calculate嵌套也可以从内向外, 以下面为例:
套娃 = calculate(CALCULATE([总数量],'销售表'[日期]=date(2021,1,1)) ,'商品表'[供商]="李四")
无论你说是从外向内:先筛选李四,再筛选2021/1/1,或者说从内向外:先筛选2021/1/1,再筛选李四,两种说法结果是一样的。
现在我们换一个公式,只筛选同一列:
套娃 = calculate(CALCULATE([总数量],'销售表'[日期]=date(2021,1,1)) ,'销售表'[日期]=date(2021,1,2))
哈罗雷球白夕尚*+权威指南作者认为是从外向内计算:理由如下

孙兴华同意上面的说法,但是孙兴华同时认为也可以从内向外计算:(结论:答案不唯一)
我们观察下面这个公式内层:
套娃 = calculate(CALCULATE([总数量],'销售表'[日期]=date(2021,1,1)) ,'销售表'[日期]=date(2021,1,2))
内层=CALCULATE([总数量],'销售表'[日期]=date(2021,1,1))
内层等价=CALCULATE([总数量],filter(all('销售表'[日期]),'销售表'[日期]=date(2021,1,1)))
再观察外层公式:
外层=calculate(内层 ,'销售表'[日期]=date(2021,1,2))
外层等价=calculate(内层 ,filter(all('销售表'[日期]),'销售表'[日期]=date(2021,1,2)))
既然内层已经删除了'销售表'[日期]的筛选,内部与外部筛选器都失效,你外层还怎么筛选2021/1/2 ,这不是典型的从内向外吗?

三、什么是固化筛选器?
固化筛选器,在PowerBI中可以通过切片器创建。

如果我们使用简单筛选器完成下面的工作:例如我有如下一张表,我想将2021年8月和2022年3月的表筛选出来

【新建表】筛选表 = FILTER(Sheet1,'Sheet1'[年份]=2021 && 'Sheet1'[月份]=8 || 'Sheet1'[年份]=2022 && 'Sheet1'[月份]=3)

我们也可以配合上节课的数据沿袭将新建表写成:
【新建表】数据沿袭 = TREATAS({(2021,8),(2022,3)},'Sheet1'[年份],'Sheet1'[月份])

// {(2021,8),(2022,3)} 我们在《DAX神功》第1卷第3回表构造函数中讲解的
// TREATAS我们在《DAX神功》第2卷第21回 讲解的,分别将2021年8月和2022年3月在年份和月份列上做记号
Ps:数量我们一般都是通过度量值得到
【度量值】结果 = CALCULATE(SUM(Sheet1[数量]),keepfilters(TREATAS({(2021,8),(2022,3)},'Sheet1'[年份],'Sheet1'[月份])))

以上我们演示的都是简单筛选器。
固化筛选器:
(1)切片器:放年和月(注意顺序)

(2)如下图

其实你一直在用固化筛选器,只是不知道它叫什么名字而已。
四、无论简单还是固化筛选器都要注意的问题
【1】被删除筛选的列如何处理(方法不唯一)

// 我故意将2021年和2022年月份错峰展示 ,让大家看看区别
【新建表】
日期表 = ADDCOLUMNS(
CALENDAR(FIRSTDATE('Sheet2'[日期]),LASTDATE('Sheet2'[日期])),
"年", YEAR ( [Date] ),
"季度", ROUNDUP(MONTH([Date])/3,0),
"月", MONTH([Date]),
"周", weeknum([Date]),
"年季度", year([date]) & "Q" & ROUNDUP(MONTH([Date])/3,0),
"年月", year([Date]) * 100 + MONTH([Date]),
"年周", year([Date]) * 100 + weeknum([Date]),
"星期几", WEEKDAY([Date])
)

【度量值】总销售 = sum('Sheet2'[销售])
【度量值】2021年销售 = CALCULATE([总销售],'日期表'[年]=2021)
// 取消了对字段【年】的筛选,但是保留了字段【月】的筛选,2022年1、3、5、6月仍然是2021年的值。所以这是错误的。
解决方案:
【度量值】2021keep = CALCULATE([总销售],KEEPFILTERS('日期表'[年]=2021))

【2】覆盖是可以跳过的
在讲Calculate嵌套运算顺序时,我当然明白覆盖是什么意思,但是我想能不能跳过这个概念?答案是可以的,就如同我们刚才遇到的问题:
【度量值】2021年销售 = CALCULATE([总销售],'日期表'[年]=2021)
我是不是也能写成:
【度量值】改2021年销售 = CALCULATE([总销售],left('日期表'[年月],4)="2021")
// 取【年月】前4个字符是2021的,能实现的方法太多了
总之,尽量避开 calculate(calculate) 套娃的方式,就跟国家普法教育宣传,目的是让你遵纪守法,而不是让你学习法律钻空子。学原理也是一样,学原理的目的就是避开原理。《权威指南》本课内容给大家例举了Calculate套娃原理,最终它也没有建议你使用。
五、这里不用Keepfilters没有发现区别
例如:计算月平均
【方法1】
【度量值】月平均 = AVERAGEX(DISTINCT('日期表'[年月]),[总销售])
【方法2】
【度量值】月平均等价 = AVERAGEX(KEEPFILTERS(DISTINCT('日期表'[月])),[总销售])
【度量值】月平均等价 = AVERAGEX(DISTINCT('日期表'[月]),[总销售])
// 权威指南上使用了KEEPFILTERS,经PowerBI 2021年10月版测试 是否使用KEEPFILTERS暂未发现区别,我个人理解Aceragex只是迭代函数,度量值转换了上下文,并没有删除日期表[月]这个列的筛选,所以是否使用Keepfilters恢复也没有区别。如果我理解的不对欢迎大家留言。


《孙兴华讲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等等