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

Power BI之DAX神功:第3卷第6回 笛卡儿积CROSSJOIN、GENERATE 和 GENERATEALL

2021-12-01 12:54 作者:孙兴华zz  | 我要投稿

《火力全开》中我只讲了一个笛卡尔积CROSSJOIN,因为他能解决99%的笛卡儿积问题。

一、GENERATE函数两张表的笛卡儿积

《DAX神功》第2卷第9回 我们做过这样一个案例,计算每个人的销售排名

【度量值】总销售 = sum( '表2'[销售])

【度量值】排名 = RANKX ( GENERATE ( ALL ( '表1'[名称] ), ALL ( '表2'[编码2] ) ), [总销售])

二、笛卡儿积并不是非用不可

我们也可以通过下面公式实现排名:

度量值 = RANKX(calculatetable(SUMMARIZE('表2','表2'[编码2],'表1'[名称]),all('表1'[名称])),[总销售])

原理:

【1】SUMMARIZE('表2','表2'[编码2],'表1'[名称]) 取表2[编码2]与表1[名称]列去重后的临时表

详见《DAX神功》第1卷第15回

【2】名次不是通过行标题筛选出来的,而是V过来的

详见《DAX神功》第2卷第5回至第9回  我们证明了名次并不筛选出来的是V过来的

我的行标题上放表1[名称],所以我必须要取消(删除)这个列的筛选功能

我要使用all('表1'[名称])取消(删除)指定列的筛选功能,就必须使用引擎,数值的引擎是Calculate,表的引擎是CalculateTable

CalculateTable(临时表,all('表1'[名称]) // 返回的这张表与临时表长像一样,只是对表1名称列删除了筛选功能的表。

【3】最后使用RankX函数

RankX(CalculateTable(临时表,all('表1'[名称])),[总销售])

PS:我这里只用了all('表1'[名称])一个调节器,你可以再加上all('表2'[编码2]),根据你自己的需求而定。总之一句话,RankX函数它行标题上的列不能有筛选功能。这些原理在《DAX神功》第2卷第5回至第9回证明过。

这样做的弊端就是速度问题,SUMMARIZE生成临时表,CalculateTable筛选临时表,现在是教学案例只有几行,如果有几十万行速度还是有区别的。这时建议使用笛卡儿积,一次完成

三、GENERATE与CROSSJOIN函数的区别

新建表1 = GENERATE ('表1',RELATEDTABLE ('表2'))

新建表2 = GENERATE ('表1','表2')

新建表3 = CROSSJOIN ('表1','表2')

新建表1 = GENERATE ('表1',RELATEDTABLE ('表2'))

新建表2 = GENERATE ('表1','表2')

新建表3 = CROSSJOIN ('表1','表2')

我们发现新建表2和新建表3结果是一样的,CROSSJOIN支持多张表笛卡儿积,GENERATE支持两张表笛卡儿积。

但是,我们观察新建表1,结果与新建表2和新建表3不同,其实当你使用CalculateTable时结果同新建表1是一样的

新建表4 = GENERATE ('表1',CALCULATETABLE( ('表2')))

Calculatetable和Calculate一样都是将行上下文转换成筛选上下文

RELATEDTABLE作用:一端找多端。一端和多端什么关系?多端可以被筛选,相当于将行上下文转换成筛选上下文。

新建表1或新建表4生成方式不只这一种:我们换一种思路

我们发现,新建表2中,编码1=编码2  就是新建表1或新建表4的样子

所以我们也可以写成:

新建表5 = filter(GENERATE ('表1','表2'),'表1'[编码1]='表2'[编码2])

// 同理我们使用CROSSJOIN函数结果相同

四、将笛卡儿积应用到数据沿袭优势明显

// 《DAX神功》第2卷第21回 数据沿袭我们讲过这个公式的原理,但是表不只两张又怎么办?

我们可以使用笛卡儿积代替Selectcolumns,使用CROSSJOIN的优势:可以一次将筛选器应用到多张表

// 至于CROSSJOIN中使用ALL、VALUES、DISTINCT的区别在这里的新建表中是看不到的。每个函数的区别我们在前面的课程中都有详细介绍。例如你配合Calculate使用时,all和其它两个函数就有区别了,VALUES和DISTINCT区别:是否满足实时参照完整性返回空行的问题。

五、显示空行的GENERATEALL函数

表2中日期不连续:没有2021/1/3和2021/1/4

新建日期表:

【新建表】根据表2在表1中拿到名称 = SUMMARIZE (RELATEDTABLE ('表2'),'表1'[名称])

【新建表】不重复日期 = VALUES('日期表'[Date])

【新建表】generate = generate(VALUES('日期表'[Date]),SUMMARIZE (RELATEDTABLE ('表2'),'表1'[名称]))

// 如果表2没有相对应的日期,笛卡儿积之后会被忽略该日期。(隐藏空行)

// 不能直接用表1中的名称列,因为表1中没有日期

【新建表】generateall = generateall(VALUES('日期表'[Date]),SUMMARIZE (RELATEDTABLE ('表2'),'表1'[名称]))

// generateall与generate相反,它显示空行

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

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

Power BI之DAX神功:第3卷第6回 笛卡儿积CROSSJOIN、GENERATE 和 GENERATEALL的评论 (共 条)

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