在 DAX 中有一个神奇的函数 ALL,被誉为 DAX 圣经的书中有专门的多页篇幅来讲解这个 ALL 以及其相关系列。在 2019年9月 DAX中又新增了一个函数 REMOVEFILTERS,那么,ALL 到底是怎么回事?与 REMOVEFILTERS 到底有何不同?如果你看 DAX圣经 你需要看很久,而罗叔则让你秒懂,永远不会错。
罗叔是宗旨是在理解透彻 DAX 后,告诉初学者以及业务用户更容易识记的规律以让大家不至于陷入技术细节。因为,BI 是业务驱动的,而不是技术驱动的。
市场占有率 - 第一次用 ALL
先看一个业务问题:市场占有率,其 DAX 计算为:
其中,
代码语言:javascript复制KPI.MarketShare% =
[KPI.Sales] / CALCULATE( [KPI.Sales] , ALL( 'Product'[类别] ) )
这是第一次接触 ALL 的合理场景。
其业务含义为:当前所选产品类别的销售额 占 所有产品类别的销售额,即:某产品类别的市场占有率。
这里的 ALL 将帮助我们似乎达到一个效果:忽略(清除)了外界的筛选并返回所有的类别。
注意这里的用词:似乎 和 效果。这里涉及到两件事:忽略(清除)筛选 和 返回所有类别。
我们等下再来看这两件事。先看另一个PowerBI中的有意思的现象。
全选 与 全不选
首先,我们先做一个度量值,如下:
代码语言:javascript复制DAX - 产品类别 是否 被筛选 = ISFILTERED( 'Product'[类别] )
其含义不言而喻。我们拖拽一个切片器如下:
现在问题来了,如果点击 全选 或 全不选(点击两次全选即可切换为全不选)会是什么结果。在看答案前,很多人或猜测:
- 猜测全选时,返回 TRUE,对吗?
- 猜测全不选时,返回 FALSE,对吗?
这种猜测很自然,但结果让你惊讶:
首先,先看全不选的时候,如下:
其次,来看全选的时候,如下:
居然也是 FALSE。于是得到一个很奇葩的结论:全选与全不选都是全不选。因此,这种全选表面上点击了全选按钮,而实际上,相当于点击了清除按钮,如下:
也就是说:点击全选等价于点击清除。
奇葩的事情并没完,罗叔带你继续飞。
一个个全选
这次我们一个一个点击选择,如下:
继续点击 家具,如下:
我去,什么鬼?居然返回了 TRUE。
强调一遍,当一个个选择直到全选时,返回了 TRUE。
到底有没有选
来看两个图:
上下两图完全一致,但筛选结果却完全不同。那到底选了没有?
总结规律
以下直接总结规律,你可以重新回看上述内容或自己做实验:
- 初始状态,没有选择任何元素,也就是某列没有被筛选。
- 直接全不选与直接全选等价,没有选择任何元素,也就是某列没有被筛选。
- 直接全选与直接全不选等价,没有选择任何元素,也就是某列没有被筛选。
- 清除选择回到初始状态,没有选择任何元素,也就是某列没有被筛选。
- 逐个选择直至全选,选择了所有元素,某列被筛选。
其状态变化图如下:
再仔细观察下 PowerBI 的切片器控件,如下:
识记 DAX 函数
将上面的经验与 DAX 函数结合,便可以得到这样的准确用词以及规律:
- 无函数,对应于【初始化】,无筛选,ISFILTERED 返回 FALSE。
- ALL,对应于【直接全选】与【直接全不选】等价,无筛选,ISFILTERED 返回 FALSE。
- FILTER( ALL( T[C] ) , TRUE() ),对应于【逐个全选】,有筛选,ISFILTERED 返回 TRUE。
- REMOVEFILTERS,对应于【清除选择】,无筛选,ISFILTERED 返回 FALSE。
其中,第三条可能有点突然,我们来观察由此构建的 DAX 表达式,如下:
代码语言:javascript复制DAX - 产品类别 是否 被筛选 = ISFILTERED( 'Product'[类别] )
DAX - ALL = CALCULATE( ISFILTERED( 'Product'[类别] ) , ALL( 'Product'[类别] ) )
DAX - FILTER.ALL = CALCULATE( ISFILTERED( 'Product'[类别] ) , FILTER( ALL( 'Product'[类别] ) , TRUE() ) )
DAX - REMOVEFILTERS = CALCULATE( ISFILTERED( 'Product'[类别] ) , REMOVEFILTERS( 'Product'[类别] ) )
DAX - VALUES = CALCULATE( ISFILTERED( 'Product'[类别] ) , VALUES( 'Product'[类别] ) )
对应的结果,如下:
尤其值得注意的是,DAX - FILTER.ALL 版本返回的是被筛选的 TRUE,由于 FILTER 是一个迭代函数,要对某列逐行考察,就如同逐个选择,因此,是被筛选的。
总结
至此可以得到非常清晰的识记方式:
- ALL - 全选,与全不选以及清除筛选等价。
- 当 ALL 位于 FILTER 等函数内时,全选后再被迭代判断而筛选,因此,是被筛选的。
- REMOVEFILTERS - 清除选择,与全选以及全不选等价。
- VALUES - 当前元素(们),形式为一个列构成的表。
这样,就可以清楚得记忆这个问题的答案了,其中DAX代码均以给出,大家可以自行尝试,示例数据为通用文件,可在入门星球获取,祝大家玩得开心。
本文内容系 DAX基础 部分,更多 DAX基础 学习请进入 DAX基础 星球,系统化学习。