文章写起来真的也挺麻烦的。坚持坚持!加油加油!
本次分享的需求描述如下:
在Power BI中创建一个页面,页面显示一个Table和两个Slicer。其中Slicer的内容也列在Table里。Table里需要一个计算值,这个计算值要求对Table中的一个非Slicer里的字段做汇总计算。
转换成显示页面如图所示。
熟悉的Product数据表。
两个Slicer分别是Brand和Color。同时Brand和Color还显示在Table里面。计算的数值内容是统计不同的Manufacturer生产多少种Product,即针对且只针对Manufacturer做分组(group by)计算Product。当选择不同的Brand和Color时,数值也要根据实际显示的Product再计算对Manufacturer做汇总。
DAX分享9效果图https://www.zhihu.com/video/1110165158554456064其实这种需求还是很常见的。不知道大家有没有什么好的方法。目前来说我觉得最简单的方法就是定义变量了。先把最简单的方法说一下,然后再把如果不用变量会遇到的问题分享一下。
var test =
VAR manu = MAX('Product'[Manufacturer])
RETURN
COUNTROWS(
FILTER(ALLSELECTED('Product'),'Product'[Manufacturer] <= manu))
就这么定义一下就ok了。so easy!
下面我们聊一聊如果不用变量可能出现的问题。
不考虑变量的话,首先对于针对其中一个字段做group by分组计算的话,这样改写filter context的行为,我们首先可以想到的是用CALCULATE函数。因为只针对Manufacturer,所以想到用ALLEXCEPT函数可以得到如下数据值列:
count per manufacturer = CALCULATE(COUNT('Product'[Product Name]),ALLEXCEPT('Product','Product'[Manufacturer]) )
er,这样做当然是不全面的。因为两个在Table里但是也显示在Slicer字段,如果选择了不同的Slicer数据时,count per manufacturer数据值是不会发生变化的。
比如,选择了Color的Azure,在Table里面显示了14条Product Name的的数据,并且都是在一个Manufacturer下面,所以,数据字段我期望的显示应该是14而不是132.
这个count per manufacturer就像是Manufacturer的属性一样了,第一次计算好了之后,就不会变化了。现在我们开始考虑怎么在数据表里面接受外来filter的影响。首先想到的函数是ALLSELECTED()。但是,ALLEXCEPT函数是不能内嵌ALLSELECTED函数的。ALLSELECTED可以考虑到外部的筛选,但是如何做group by分组计算呢?此路不通。然后我想到了万能的CALCULATE+FILTER,FILTER里面可以有ALLSELECTED函数,但是后面的参数这么实现动态的Manufacturer的抓取呢?
如果看过我之前分享的HASONEVALUE的同学,会不会想到用这个HASONEVALUE呢?我通过HASONEVALUE去抓取Slicer是否被选择,然后再分情况计算,就像之前DAX分享8里面的做法那样呢?嘿嘿,挺不错的吖~~不过,也不对。这里重点说一下!HASONEVALUE或者HASONEFILTER说,如果数据字段被筛选了,就是TRUE,没有被筛选就是FALSE。什么要被筛选了呢?在Slicer里面选择算是,在Table里面作为字段也算是~~~也就是说,对于这里的Brand和Color,HASONEVALUE的返回值永远都是TRUE。是不是很酸爽很好玩。
er,如果按照SQL逻辑来说,我比较期望,让我的查询结果,先和Brand,Color做关联,然后再去计算group by的分组计算。想法是好的,但在实现的时候,报表其实做的是一个over partition的开窗计算,先计算好结果,然后又成为了一个属性。
好吧,现在你明白了吧。有的时候,比如动态查询的时候,就是非变量不行的时候了。记住!敲黑板!针对动态的filter context的时候,首选变量表达式。so easy!
欢迎关注DAX Share!