欢迎光临散文网 会员登陆 & 注册

Power BI之DAX神功:第4卷第4回 使用虚拟关系在DAX中转换筛选器

2021-12-19 16:20 作者:孙兴华zz  | 我要投稿

一、区间范围处理方案

需求:每个促销品在促销日期范围内的销售情况

如上图所示,每个商品都有它的促销期,根据相关规定一般情况下(不排除有特例),商品促销期不得超过14天,且促销期过后必需恢复原价卖至少7天,才能再次促销。假设:一台游戏机原价3899,促销价格2899,2021/1/1~2021/1/14促销14天后,2021/1/15要恢复原价3899,如果我还想继续促销,那我的促销价格必须低于2899,例如促销价2898,并且要注明原价是2899,不能写3899。否则涉嫌价格欺诈。假设2021/1/15此商品正常价格跌至1999元,可以修改价格,但是不能使用促销标志。此规定暂时不适用于电商。

很多商家并没有按此规定执行,买方懂的人少,就算买家懂去举报的也是少数。你分析,当一个商家卖的价格比别人都便宜时(前提是正品),那举报他的肯定不是正常的消费者。

上面两张表,促销表列出了四种商品的促销日期。但是我们无法直接建立关系。

【1】数据清洗

导入促销表时,先进入PowerBI的PowerQuery模块,使用M函数增加两个列

如果你的表格本身就是有开始日期和结束日期这两列,那么你就可以省略数据清洗的步骤,我一直告诉大家数据清洗不是必需的,是表格不规范造成的。

【2】使用商品编码,建立关系

【3】编写度量值

《DAX神功》第1卷第14回讲到,var x=SELECTEDVALUE('表'[列]) 代表当前行

《火力全开》笔记27.3.3  DATESBETWEEN函数取区间范围

【4】返回结果

二、按促销类别计算方法同上

【1】对促销表利用M函数进行数据清洗

Ps:如果促销表中有开始和结束日期这两列,数据清洗可以省略。

【2】按下图建立多表关系

【3】写度量值

【4】返回结果

其实就是修改一下字段名称,方法是没有区别的。但是《权威指南》本节课提供的案例使用了CONTAINS函数,声明人家案例对,但是有局限性,也就是说你的促销品或类别必须是整月促销。

三、CONTAINS函数

每个国家都有自己的法律法规,也许国外没有促销时间的限制,人家就整月做促销。《DAX权威指南》是高飞老师翻译的,并不是作者,所以案例也不会考虑我们国家的情况。

《火力全开》笔记24.01 我们讲了CONTAINS函数

语法:CONTAINS(表,列名1,查找的值1,列名2,查找的值2,...)

如果第1参数表至少存在一行满足所有列名都有对应的查找的值,返回 true,否则返回 false。

注意:列名必须属于第一参数或第一参数的扩展表。(扩展表原理就不再重复了)

因为要考虑年和月,所以我们需要更多颗粒度,需要新建日期表:

【1】新建动态日期表

【2】日期表与销售表建立关系

【3】从促销表中多条件查找

CONTAINS('促销','促销'[年],'日期表'[年],'促销'[月],'日期表'[月],'促销'[类别],'商品表'[类别])

但是CONTAINS返回的是True和False

现在我问你,销量在哪张表中?答:在销售表中,现在应该用上面的条件筛选哪张表?答:筛选销售表。

FILTER('销售表',CONTAINS('促销','促销'[年],RELATED('日期表'[年]),'促销'[月],RELATED('日期表'[月]),'促销'[类别],RELATED('商品表'[类别])))

// 因为Filter创建的是行上下文逐行迭代,销售表是多端,日期和商品表是一端表,多端找一端使用关系函数RELATED

【4】最后度量值

方法一:Calculate([总销量],filter创建的表)

如果你感觉filter遍历整个销售表太慢了,也可以利用summzrize+扩展表原理,得到你需要的行和列。详见本文章:五、利用扩展表与交集的特性公式tb1 来代替销售表

方法二:Sumx(filter创建的表,'销售表'[销量])

返回结果:

《权威指南》给出的建议,它认为这样写速度慢,因为Filter迭代的整个销售表如果数据量大会影响性能。Sumx又重复迭代每一行,数据量大了以后,这是非常可怕的事情。

四、利用数据沿袭特性

《DAX神功》第2卷第21回 我们详细讲解了数据沿袭

【1】获取促销表中的所有列

如果在新建表里面,我们可以使用SUMMARIZECOLUMNS,但是要写到度量值中,由于SUMMARIZECOLUMNS不支持大部分度量值,我们选择使用SUMMARIZE。

tb1 = SUMMARIZE('促销','促销'[类别],'促销'[年],'促销'[月])

他返回的就是促销表,与我们使用表构造函数写出来的{"张三","李四","王五"}是一个意思

【2】数据沿袭打标记要换SUMMARIZE顺序来

tb2 = TREATAS(tb1,'商品表'[类别],'日期表'[年],'日期表'[月])

按常理来说,SUMMARIZE这一步是多余的,我直接使用促销表不香吗?问题就在数据沿袭这里,他需要按你提取出来的列顺序去在相关表上打标签。

【3】写出完整度量值

《DAX神功》第2卷第21回 我们证明了

TREATAS({"张三","李四"},Sheet1[姓名])    相当于   'Sheet1'[姓名] in {"张三","李四"}  

在Calculate的筛选器中使用这种布尔筛选时,相当于指定列取消筛选,恢复筛选的方法可以使用Keepfilters。

返回结果:

五、利用扩展表与交集的特性

《DAX神功》第3卷第8回 INTERSECT函数

销售表是多端表,商品表和日期表都是一端表,并且连线成一对多关系,那么,销售表的扩展表就是销售表、商品表、日期表中的所有列。我可以使用SUMMARIZE取我需要的列:

tb1 = SUMMARIZE('销售表','商品表'[类别],'日期表'[年],'日期表'[月])

让这张表与

tb2 = SUMMARIZE('促销','促销'[类别],'促销'[年],'促销'[月])

取共有部分

这两张表在INTERSECT中的位置一定要注意:

《DAX神功》第3卷第8回 我们提到INTERSECT函数交换参数位置影响数据沿袭

图片来自《DAX神功》第3卷第8回

我们需要保留tb1中列的数据沿袭(列名虽然一样,但是不来自一张表,tb2都来自己促销表,而tb1来自销售表的扩展表),但又需要tb2中的数据,这时使用INTERSECT取交集,保留第1参数数据沿袭是最好的方法。

返回结果:

六、总结

从速度上讲利用数据沿袭特性利用扩展表与交集的特性,会比CONTAINS函数快,但是国内企业利用率更高的还是我第一个就讲的DATESBETWEEN函数。

《孙兴华讲PowerBI火力全开》PowerBI必学课程

https://www.bilibili.com/video/BV1qa4y1H7wp

《DAX神功》文字版合集:

https://www.bilibili.com/read/readlist/rl442274

《DAX神功》视频版合集:

https://www.bilibili.com/video/BV1YE411E7p3

《DAX神功番外篇》文字版合集:

https://www.bilibili.com/read/readlist/rl478271

PowerBI(DAX函数)、PowerQuery(M函数)、Python办公自动化、Python爬虫、Python数据分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等

https://www.bilibili.com/read/cv10222110

Power BI之DAX神功:第4卷第4回 使用虚拟关系在DAX中转换筛选器的评论 (共 条)

分享到微博请遵守国家法律