一对一关系指南
本文专为使用 Power BI Desktop 的数据建模人员设计。 它指导你如何处理一对一模型关系。 如果两个表都包含一列唯一公用值,可以创建一对一关系。
注意
本文不涵盖对模型关系的介绍。 如果你对模型关系、其属性或配置方法并非完全熟悉,建议先阅读 Power BI Desktop 中的模型关系一文。
此外,还应了解星型架构设计,这一点也很重要。 有关详细信息,请参阅了解星型架构和 Power BI 的重要性。
涉及一对一关系的场景有以下两种:
行数据跨表:单个业务实体或主题加载为两个(或更多)模型表,可能是因为它们的数据源来自不同的数据存储。 此方案对于 维度表很常见。 例如,主产品详细信息存储在运营销售系统中,而附属产品详细信息则存储在其他源中。
但是,将两个事实表与一对一关系相关联是不寻常的。 这是因为这两个事实数据表都需要具有相同的维度和粒度。 此外,每个事实数据表都需要唯一的列才能创建模型关系。
退化维度
当事实数据表中的列用于筛选或分组时,可以考虑在单独的表中提供它们。 这样一来,就可以将用于筛选或分组的列与用于汇总事实行的列分隔开来。 这种分隔可以:
- 减少存储空间。
- 简化模型计算。
- 有助于提高查询性能。
- 向报表作者提供更直观的“数据”窗格体验。
请考虑名为 Sales
的源表,该表将销售订单行引用详细信息存储在两列中。
OrderNumber
列存储订单号,OrderLineNumber
列存储订单中的一系列订单项。
在下图中,请注意,订单号和订单行号列尚未加载到 Sales
表中。 而它们的值用于创建名为 OrderLineNumberID
的 代理键列。 (键值的计算方法为,将订单号乘以 1000,然后再加上订单项号。)
Sales Order
维度表为报表作者提供了丰富的体验,其中包含两列:Sales Order
和 Sales Order Line
。 这些特定列资源支持需要对订单和订单行进行筛选、分组或向下钻取的报表设计。
由于 Sales Order
表派生自销售数据,因此每个表中的行数应完全相同。 此外,每个 OrderLineNumberID
列之间应有匹配的值。
跨表的行数据
请考虑涉及两个一对一相关维度表的示例:Product
和 Product Category
。 每个表表示导入的数据,并具有一个包含唯一值的 SKU
(保留单位)列。
下面展示了这两个表的部分模型图。
第一个表命名为 Product
,其中包含三列:Color
、Product
和 SKU
。 第二个表命名为 Product Category
,其中包含两列:Category
和 SKU
。 一对一关系将两个 SKU
列关联起来。 关系为双向筛选,对于一对一关系,总是如此。
为了帮助描述关系筛选器传播的工作原理,下图显示了一些表行。 本文中的所有示例都以此数据为依据。
下面的项目符号列表描述了两个表的行的详细信息:
- 编号为
Product
的表共有三行:SKU
CL-01、Product
T 恤、Color
绿色SKU
CL-02,Product
牛仔裤,Color
蓝色SKU
AC-01、Product
帽子、Color
蓝色
Product Category
表有两行:SKU
CL-01、Category
服装SKU
AC-01、Category
配件
请注意,Product Category
表中不包含产品 SKU CL-02的一行。 本文稍后将讨论缺少此行的结果。
在“数据”窗格中,报表作者在两个表中查找与产品相关的字段:Product
和 Product Category
。 现在来看看添加有两个表中字段的表视觉对象是什么样的。 在此示例中,SKU
列源自 Product
表。
请注意,产品 SKU CL-02 的 Category
值为 BLANK。 这是因为此产品的 Product Category
表中没有相应的行。
建议
若为跨模型表的行数据,建议尽可能避免创建一对一模型关系。 这是因为此设计可以:
- 导致“数据”窗格混乱,列出不必要的表。
- 导致报表作者很难找到相关字段,因为它们分布在多个表中。
- 限制创建层次结构的能力,因为其级别必须基于同一表中的列。
- 在表之间的行不完全匹配时导致意外结果出现。
具体建议因一对一关系是源组内还是跨源组而异 。 有关关系评估的详细信息,请参阅 Power BI Desktop中的
源组内一对一关系
如果表之间是一对一源组内关系,建议将数据合并到一个模型表中。 可以通过合并 Power Query 查询来执行此操作。
以下步骤提供了一种合并和建模一对一相关数据的方法。
合并查询:合并两个查询时,考虑每个查询中数据的完整性。 如果一个查询包含一组完整的行(如主列表),请将另一个查询与它合并。 将合并转换设置为使用左外部联接(即默认联接类型)。 这种联接类型可确保你保留第一个查询的所有行,并使用第二个查询的任何匹配行进行补充。 将第二个查询的所有必需列扩展到第一个查询中。
禁用查询负载:请务必对第二个查询禁用负载。 这样,它就不会将其结果加载为模型表。 此配置减少了数据模型存储大小,并有助于让“数据”窗格保持整洁。
在我们的示例中,报表作者现在可在“数据”窗格中找到一个名为
Product
的表。 它包含所有与产品相关的字段。替换缺失值:如果第二个查询包含不匹配的行,那么从它引入的列中会显示 null 值。 视情况考虑使用标记值替换 null 值。 当报表作者按列值筛选或分组时,替换缺少的值尤为重要,因为报表视觉对象中可能会显示 BLANK。
在下图中,请注意,产品 SKU CL-02 的类别现在显示为 [未定义]。 在查询中,null 类别已替换为此标记文本值。
创建层次结构:如果当前合并的表的列之间 存在关系,不妨创建层次结构。 这样,报表作者会快速发现报表视觉对象钻取机会。
在我们的示例中,报表作者现在可以使用具有两个级别的层次结构:
Category
和Product
。
如果你更倾向于单独的表有助于整理字段,仍建议合并到单个表中。 仍可以整理字段,但要改用显示文件夹 。
在我们的示例中,报表作者可以在 Marketing
显示文件夹中找到 Category
字段。
如果你仍决定在模型中定义一对一源组内关系,请尽可能确保关联表中有匹配行。 由于一对一源组内关系被评估为常规关系,因此数据完整性问题可能会在报表视觉对象中显示为空白。 (例如,本文中显示的第一个表视觉对象中就有 BLANK 分组。)
跨源组一对一关系
如果表之间是一对一跨源组关系,除非预先合并数据源中的数据,否则没有替换模型设计。 Power BI 会将一对一模型关系评估为有限关系。 因此,请注意确保相关表中有匹配的行,因为查询结果中会剔除不匹配的行。
现在来看看添加有这两个表(之间存在有限关系)中的字段的表视觉对象是什么样的。
使用跨源组关系的第一个表视觉对象仅显示两行。 缺少产品 SKU CL-02,因为 Product Category
表中没有匹配行。 第二个表视觉对象基于模型中的单个合并表,显示三行。
相关内容
有关本文的详细信息,请参阅以下资源: