Power BI:保持数据建模原则并处理多对多关系
现在在哪里
Power BI的除了可以进行漂亮的可视化,更多内容隐藏在表面下的建模本身。
Power BI 数据建模:
- 鼠标拖拽形成关系
- 处理筛选器方向
- 处理关系的激活与非激活
- 理解维度建模与数据仓库
- 处理多对多关系
Power BI 深度数据建模:
- 维度建模与自由建模(不受维度和事实的限制)
- 用DAX建立虚拟关系(集合,contains,treatas)
- 用DAX表函数建立新表
- 扩展表原理
- 性能优化
- 行级别安全性及传递
本次关注其中一个问题:多对多关系。对此,SQLBI的大师已经给出近乎终极全面的参考,可以参考阅读:
这里更多从简单的角度来看Power BI中处理多对多关系的方法。
如何看懂Power BI的数据模型
对于普通用户来说,没有专业的数据库背景,我们可以这样来理解Power BI中的数据模型:
作为一个最佳实践:请确保Power BI模型中并不出现两个箭头的连线,下面的图是应该避免的:
筛选器的方向指导分析的思路
如果想知道各省分别有多少销售额,就是从地区来筛选订单;而如果想知道单价大于1000的订单都卖到过哪些地区则从订单来筛选地区。
可以这么说,Power BI的双向筛选器是给真正知道他在做什么的分析师用的,在默认状态下务必使用单向筛选器,也就是将筛选器方向全部改为单向。
往往针对一个特定的主题加载相关的数据,例如在上例中要分析销售情况,是不需要加载库存情况数据的。在分析时(在Power BI画布上拖拽时)可以遵循下面的思路:
始终考虑 从什么角度来观察什么问题。
在这个案例中:
筛选器的方向通常指明了观察问题的方向。也就是:
- 从地区的角度看销售额大小
- 从客户的行业角度看销售额大小
- 从产品的类别角度看销售额大小
- 从特定年份不同月份角度看销售额大小
除了看销售额大小,还可以看:利润,利润率,同比利润率等等。通过这些套路,可以完成对数据的初步探索。
如果注意观察思维的语义,不难发现:
- 思考的角度(通常称为维度),放在Power BI的坐标轴字段。
- 思考的问题(通常称为度量值),是一个能用数值表示的量,放在Power BI的值字段。
Power BI提供了对度量值的默认算法,包括:求和,计数,非重复计数,求平均等。而最佳实践是不依赖Power BI提供的默认计算,而是自己显式地定义度量值,哪怕仅仅是求和。例如:
- 总销售额 = SUM( 订单[销售额] )
- 总利润率 = SUM( 订单[利润] ) / SUM( 订单[销售额] )
总利润率是Power BI无法默认实现的,必须由设计师显式定义。
Power BI 中的关系
Power BI 中的关系有以下这几种可能:
类型 | 关系 | 交叉筛选器方向 |
---|---|---|
1 | 多对一 | 单一 |
2 | 多对一 | 两个 |
3 | 一对多 | 单一 |
4 | 一对多 | 两个 |
5 | 一对一 | 两个 |
如果知道正在做什么,那不需要遵守下面的约定,如果不知道正在做什么,请遵守:
- 保持关系仅限于:多对一或一对多。
- 保持筛选器方向仅限于:单一。
由于多对一和一对多的意思是一样的,所以统一叫做一对多。此时,我们的模型就仅仅存在一种模型中的关系那就是:保持单一筛选的一对多关系。
这样就将一团复杂简化到只有一条原则的状况,也就实现了文初的模型:
保持这样的简单关系就像保持简单的人际关系一样,生活和模型都本应简单。在此基础上,模型就像生活偶尔会出现复杂点的关系,怎么办?
什么是多对多关系
说:有猫和狗,有肉和奶。问:猫吃了什么?狗吃了什么?肉都谁吃的?奶都谁喝的?
这就是典型的多对多关系。它表示了事物之间的一种可能关系。如果这个问题不够触动的话,可能更熟悉的是:
- 不同类产品卖给过多少客户?
- 不同行业职业客户买过多少种产品?
- 不同省份提供过多少种产品?
- 不同类产品从多少个城市进过货?
解决多对多问题的第一步是识别多对多问题,例如:一种产品可能卖发给过多个客户,一个客户可能买过多种产品。因此,这种产品与客户的购买关系就是多对多的。
在Power BI中处理多对多关系
首先,在Power BI中并不直接支持多对多关系;根据上述的原则:保持单一筛选的一对多关系也无法反应这样关系。
这时需要一个桥,桥是一种形象的称呼。可以这样理解:产品 和 客户 之间无法直接建立多对多的关系,但可以通过一个中间表作为桥一样(称为桥表),来实现产品 和 客户 之间的连接。
例如:
可以看出:
- 进货单正是货源地与产品之间的桥;
- 订单正是产品与客户之间的桥。
它们通常有这样的特点:
- 产品,客户,货源地表示一种实体(现实中存在的物体)。
- 订单(以及订货单)表示一种谁(客户实体)在什么时间与谁(产品实体)发生关系的记录。
也就是说:实体是通过表来表示的;实体之间发生关系会形成记录,也用表来表示。从这个意义上,订单已经不再强调它按维度建模理论中的事实表角色,而是强调它连接了两个实体作为关系记录而存在。
在Power BI中实现基于多对多关系的计算
在Power BI中实现回答上述问题,可以常规通度量值加入桥表作为筛选器处理,:
客户数 = CALCULATE( COUNTROWS( 'tb客户' ) )
客户数(桥:订单) = CALCULATE( COUNTROWS( 'tb客户' ) , 'tb订单' )
效果:
可以看出常规度量值的计算是无效的,原因在于常规度量值只能满足按照箭头的方向传递。而加入了桥表作为筛选器就将本来断开的两个实体连接起来,使得原度量值恢复了计算能力。
可以看出只需要按 CALCULATE( 常规度量值 , 桥 ) 的形式来改写常规度量值,就可以实现基于多对多关系的计算。以上述为例,它表明了这样一种意义: 基于产品与客户的关系记录 订单表 来看,按产品的属性:类别,分别计算客户数度量值是多少。
值得强调的是,这仍然是一个模式(套路):
- 基于实体与实体的关系记录
- 按某实体的属性作为观察出发点
- 计算与另一实体有关的度量值
这三条几乎严格地给出了这个套路,这要遇到类似问题,都可以这样套用。
使用套路处理更多案例
为了加深对这个套路的理解,下面处理更多例子来说明。
不同行业职业客户买过多少种产品
请结合上述关系图理解:
产品数 = CALCULATE( COUNTROWS( 'tb产品' ) )
产品数(桥:订单) = CALCULATE( COUNTROWS( 'tb产品' ) , 'tb订单' )
效果:
不同省份提供过多少种产品
请结合上述关系图理解:
产品数 = CALCULATE( COUNTROWS( 'tb产品' ) )
产品数(桥:进货单) = CALCULATE( COUNTROWS( 'tb产品' ) , 'tb进货单' )
效果:
注意:这里用到了另一个桥表进货单来连接地区和产品。
不同类产品从多少个城市进过货
请结合上述关系图理解:
货源地数 = CALCULATE( COUNTROWS( 'tb货源地' ) )
货源地数(桥:进货单) = CALCULATE( COUNTROWS( 'tb货源地' ) , 'tb进货单' )
效果:
至此,多对多关系已经可以处理。
跨越关系的多对多关系
现实中除了存在两个实体的多对多关系,还可能存在更加隐蔽和复杂的多对多关系,为了方便连贯思考,再次使用上述的模型如下:
可能存在这样的问题:不同货源地省份的供货都销售给多少客户?
这是在研究 货源地 和 最终客户 的关系。这就像一个跨越崇山峻岭的多对多关系,但正确的处理方法是不变的:常规通度量值加入桥表作为筛选器处理。
问题来了, 货源地 和 最终客户 之间没有桥怎么办,其实不是没有桥,而是有“两座桥”。一座桥用来连接货源地和产品,叫:进货单;另一座桥用来连接产品和客户,叫:订单。
所以:
客户数 = CALCULATE( COUNTROWS( 'tb客户' ) )
客户数(桥:订单) = CALCULATE( COUNTROWS( 'tb客户' ) , 'tb订单' )
客户数(桥:订单 进货单) = CALCULATE( COUNTROWS( 'tb客户' ) , CALCULATETABLE( 'tb订单' , 'tb进货单' ) )
效果:
也就是说,把多个桥表装到一起作为筛选器就可以处理关联式的多对多关系。
总结
在Power BI的数据建模中:
- 如果不知道正在做什么,请遵守:保持单一筛选方向的一对多关系。
- 筛选的方向提示了从...角度去看...问题。
- 度量值M2M = CALCULATE(度量值,桥表)。
- 度量值M2M2M = CALCULATE(度量值,CALCULATETABLE(桥表1,桥表2))。
- 桥表是记录了实体与实体关系的记录表,通常可能是事实表。