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

Power BI之DAX神功:第4卷第7回 通过桥接表实现多对多关系

2021-12-21 18:35 作者:孙兴华zz  | 我要投稿

一、前言

《权威指南》在这节课用的案例我是外行看不懂。引用书中一句话:“银行一个账户可以属于多个客户,一个客户可以拥有多个账户”。我接触银行是以一个储户的身份接触的,对我而言,我可以在银行开多个账户,但是一个账户不可能有多个人。比如你叫张三,你在银行存款10万,你这个账户名下还有我,我把你这10万取走了。这叫什么事呀?但是我相信书中的案例一定有他的道理,因为我是外行我不懂。(所以说数据分析不懂自己的业务=零)

但是我可以举一反三:下面是六套房子的产权人名单,房产证可以写多人

如上图所示,以孙兴华为例,房产证ID-1,是孙兴华自己买的,ID-5是孙兴华和沙织一同购买,ID-6是孙兴华和帕拉斯一同购买。那么这六套房中产权人有几个?答案是4个

二、多对多关系有两种情况

网友质疑《权威指南》本节案例中的Accounts和Customers怎么可能是多对多关系呢?

因为多对多关系有两种不同情况

第1种情况:就是我们最常见的,两张表学号、课程编号都有重复

我们的处理方法:按业务将其中一张表拆分成两个一端表,建立一对多关系

当然也可以建立多对多关系,我们将在《DAX神功》第4卷第9回进行讲解但是不推荐使用。

第2种情况:通过一对多关系多对一关系共同创建的模型,也叫多对多关系。

而书中讲的桥接表案例就是在处理这第2种情况。还记得我告诉大家,能用1张表不用2张表,能用2张表不用3张表,从4张表开始不是高手就是笑话,如果你信我,这个问题就避坑了。什么是桥接表,当两个一端表无法建立关系时,通过一张多端表将两张一端表连接起来。但是这张多端表可是有讲究的。

桥接表(Bridge Table,简称BT,听这简称就懂了)是比较特殊的表。

在数据库的建模时,会遇到具有层次结构的维度表,对于这样的表有一种建模方式是建立父子表,即每条记录上包括一个指向其父记录的字段。这种父子表的建立在层级深度可变时尤其有用,是一个紧凑而有效的建模方式。所以学习桥接表前必需先知道父子层级结构。详见《DAX神功》第3卷第2回

三、利用M函数制作桥接表

下图层级关系这张表就是桥接表,因为房产证和花名册你无法直接建立关系。

我们需要使用M函数制作它,这个案例简单你用DAX实现也可以,但是当情况变得复杂以后,数据清洗还是M函数更专业。

Ps:发票表中的退款是什么意思?你买套期房就明白了,交房时会有测绘,当房子建筑面积低于合同面积时,会有退款。(不过一般都补款,建筑面积你个人没法算,只有专业机构才能测。一旦建筑面积写在房产证上,这个面积就是合法的,你卖房时也会按照这个面积执行)

【1】将房产证这张表导入PowerQuery,增加一个步骤,命名:修改列

【2】对产权人列进行扩展

返回结果:

【3】将花名册导入PowerQuery,两张表做合并查询(通过产权人和姓名建立关系)

我们展开花名删那一列,只保留房主ID

返回结果:

最后:删除产权人列即可。

四、体验多对多关系第2种情况

凡是一端可以直接筛选多端的关系都是一对多关系:例如下图所示我们可以用姓名筛选成绩,用课程名称筛选成绩,因为两个一端表都可以筛选多端表。

但是,当我们将今天的案例导入后:(下图点击后放大)

现在,如果我想使用花名册中的姓名去筛选发票表中的金额,可是箭头不通呀

方法1:在模型中将层级关系和房产证这两张表改成双向,缺点改变了整个模型关系。

方法2:通过CROSSFILTER建立只有这一个度量值生效的双向关系。

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

返回结果:

双向筛选:如果直接在模型上改双向箭头会影响其它度量值,即便使用CROSSFILTER虽然可以无视其它度量值,但是可能会使数据模型产生歧义。我会在《DAX神功》第4卷第12回进行讲解

五、回忆我们讲双向箭头时的案例

下图是《DAX神功》第1卷第2回使用过的案例:

我们将表2和表3改成双向箭头(使用CROSSFILTER结果是一样的)

建立度量值:

你看看结果是不是错的:

原理:没有使用桥接表,也并不是所有情况都能用桥接表完成。因为《DAX神功》第1卷第2回我要证明双向箭头有问题不建议你使用故意写的几个表。所以我经常告诉大家,双向箭不要用,多对多关系很复杂!表格尽量少!否则原理学到饱!

六、数据沿袭/扩展表可以解决问题

保留数据沿袭的函数我们讲了很多,第一个想到的就是TREATAS它能修改沿袭,还有一个我们在《DAX神功》第2卷第21回最后那个图片中展示给大家了。SUMMARIZE从销售表里获取会员卡号去重后的表,再通过ADDColumns添加列适配度量值,如果没有保留数据沿袭,你能给它适配度量值吗?《DAX神功》第3卷第5回、第4卷第4回也多次使用了这个方法,同时在《DAX神功》第3卷第12回 我们学习了扩展表原理

其实我讲上面这段话的意思就是告诉大家:因为知识太多,很可能你学完就忘记了。但是我使用的知识都是讲过的,而不是凭空给你堆出来的名词。

回到我们房产证的案例中:

【1】扩展表方法处理问题

层级关系这张表,它的扩展表是:层级关系+房产证+花名册 这三张表所有列,我们使用扩展表筛选最简单的方法。

// 同时解决了行和列的筛选

【2】利用数据沿袭特性

要分开处理行和列的问题

以上两个度量值都能实现与扩展表一样效果,虽然相对复杂了。但是当两张表不在一个存储模式中,也就是处于弱关系时,扩展表只是它本身,那时你用不了扩展表原理。详见《DAX神功》第4卷第6回。如果是弱关系可以考虑使用CROSSFILTER

七、再谈不符合实时参照完整性的情况

假设我们给发票发增加一行:房产证表中没有520这个ID

发票表

如果这个时候使用双向关系(无论是改箭头,还是CROSSFILTER),当你使用产权人筛选时,都会显示空行,因为产权人ID=520他不知道对应的值是什么,在房产证这张表里没有号码。如果使用数据沿袭或扩展表就避开了这个问题。

当然你用姓名筛选时因为新增的520是房产证ID,不显示空行,但是总计仍然是697

注:总金额是修改成双向关系后直接使用【总金额】度量值,换成CROSSFILTER方法也可以。

但是这里就出现一个业务问题,你的分析中是否要避开空行?如果不想避开未匹配值的数据而影响最后结果,那就使用CROSSFILTER临时启用双向箭头。否则可以使用后三种情况。由于后三个度量值:你写成了calculate(计算器,筛选器)  ,它的筛选器被强制激活了,所以忽略未匹配的值。

当你在模型中修改成双向箭头,使用度量值 总金额=sum('发票表'[金额])

或者使用CROSSFILTER函数改变关系时:(CROSSFILTER是调节器不是筛选器)都是由行标题来筛选的,所以不忽略未匹配的值。

《孙兴华讲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卷第7回 通过桥接表实现多对多关系的评论 (共 条)

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