Power BI 中如何通过非唯一的 Col B 创建 Data Model?
结论
dim_table3[Col B] 唯一,并分别以 1:* 关系连接两张表,这个模型可以保留,用于按 Col B 筛选和汇总两表数据。不过,模型没有定义 Table 1 与 Table 2 的明细行如何配对,直接把两边的未聚合字段放进同一个 table visual,不一定能正常展示。
具体做法取决于展示需求:
- 按 Col B 比较两表指标时,使用
dim_table3[Col B]分组,配合两表各自的度量值。 - 按 Table 1 的 Col A 展示 Table 2 中相同 Col B 的数据时,添加显式传递 Col B 筛选的度量值。
- 需要展示两表所有匹配明细时,按业务规则在数据源或 Power Query 中连接;如果要求逐条对应,还需要更细的关联键。
仅将 Relationship 2 改为 Both,仍无法解决所有明细展示问题。
为什么已有关系仍然报错
单向关系无法让 Col A 筛选 Table 2
当前筛选方向是:
dim_table3 → Table 1
dim_table3 → Table 2
使用 dim_table3[Col B] 时,筛选可以同时传给两张表。使用 Table 1[Col A] 时,筛选则停留在 Table 1,无法沿单向关系返回 dim_table3,也就无法继续筛选 Table 2。
Col A 在 Table 1 中唯一,说明它可以标识 Table 1 的一行。由于 Table 2 没有对应的 Col A,模型只能通过 Col B 找到一组相关记录。
Both 改变筛选传播,不改变明细匹配规则
将 Relationship 2 改为 Both 后,可以形成:
Table 1 → dim_table3 → Table 2
沿这条路径,Table 1 可以筛选 Table 2 的度量值。但如果 visual 只包含两张表的未聚合列,仍会遇到跨越两个“多”端的分组问题。
Power BI 的常规关系支持从“多”端向“一”端进行表扩展,双向筛选不会改变这一规则。因此,Both 无法自动连接两边的所有明细。具体机制见 Microsoft Learn:模型关系。
Col B 相同也只表示记录属于同一个组。例如:
Table 1:
Col A Col B
A1 X
A2 X
Table 2:
Col B Status
X Open
X Closed
按 Col B 匹配会得到四种组合。仅凭这些字段,无法判断 A1 应该只对应 Open,还是只对应 Closed。
方案一:保留单向关系,用度量值建立展示条件
如果业务规则是“每个 Col A 展示其 Col B 对应的 Table 2 记录”,可以保留现有两条单向关系,创建以下度量值:
Matched Rows =
VAR CurrentB =
VALUES('Table 1'[Col B])
RETURN
CALCULATE(
COUNTROWS('Table 2'),
KEEPFILTERS(
TREATAS(
CurrentB,
'Table 2'[Col B]
)
)
)
TREATAS 将当前 Table 1 中的 Col B 值作为筛选条件应用到 Table 2,KEEPFILTERS 则让这些条件与已有的 Table 2 Col B 筛选取交集。TREATAS 的用途和限制见 Microsoft Learn:TREATAS。
接着配置 table visual:
- 添加
Table 1[Col A]。 - 添加需要展示的 Table 2 字段,例如
Table 2[Status]。 - 添加
[Matched Rows]。 - 在该 visual 的筛选器中设置
[Matched Rows] > 0。
这个度量值会判断每个“Col A + Table 2 字段值”组合在相同 Col B 下是否有符合条件的 Table 2 记录。没有匹配行时,COUNTROWS 返回 BLANK,见 Microsoft Learn:COUNTROWS。
在前面的示例中,A1、A2 都会分别显示 Open 和 Closed。这是按 Col B 匹配的结果,两表之间仍没有更细的一一对应关系。
如果需要展示金额等汇总值,可以将代码中的:
COUNTROWS('Table 2')
替换为相应表达式,例如:
SUM('Table 2'[Amount])
Amount 是示例列名,需要替换为实际字段。同一 Col B 对应多个 Col A 时,同一组金额可能出现在多个 Col A 行上,金额分摊仍需另行处理。
已使用 Both 时的简化方式
如果模型只有这条有效筛选路径,且 Relationship 2 已设置为 Both、Relationship 1 保持单向,可以先添加一个普通度量值:
Table2 Rows =
COUNTROWS('Table 2')
将它与两表字段放入 visual,并设置 [Table2 Rows] > 0。此时筛选通过关系传播,度量值中无需再使用 TREATAS。
两种方式选一种即可。保留单向关系并使用 TREATAS,可以将跨表筛选限定在指定度量值内;使用 Both 会影响整个模型的筛选行为。如果模型存在其他路径,还需检查是否有歧义。
方案二:按 Col B 汇总时,直接使用公共维度
如果只需比较同一 Col B 下两张表的指标,可以直接使用当前模型,创建以下度量值:
Table1 Rows =
COUNTROWS('Table 1')
Table2 Rows =
COUNTROWS('Table 2')
在 visual 中放入:
dim_table3[Col B]
[Table1 Rows]
[Table2 Rows]
两条关系都保持 Single、Active。每一行的粒度都是 Col B,无需让两张明细表相互筛选。通过公共维度连接多张事实表也是微软建议的建模方式,见 Microsoft Learn:多对多关系建模指导。
方案三:需要完整明细时,明确执行连接
如果报表需要一张固定的明细清单,可以在数据源中创建连接查询。以下是 SQL 示例,表名的引用方式需按数据库调整:
SELECT
t1.[Col A],
t1.[Col B],
t2.[Status]
FROM [Table 1] AS t1
LEFT JOIN [Table 2] AS t2
ON t1.[Col B] = t2.[Col B];
将查询结果作为一张表加载后,visual 就可以直接使用其中的列。
这种连接会产生重复:同一个 Col B 在 Table 1 有 m 行、在 Table 2 有 n 行,匹配后会生成 m × n 行。如果这些组合不符合业务含义,就需要补充订单行号、明细 ID 等真实关联键,或提供明确的映射表。
即使 Table 1 的 Col A 唯一,只要 Table 2 缺少对应字段,就不能直接用它关联两表。
DirectQuery 和数据检查事项
仅凭 DirectQuery 无法解释这次报错,还需要确认 Table 1 与 dim_table3 的存储模式及数据源。
如果 dim_table3 是 Import 表、Table 2 是 DirectQuery 表,两者跨 source group 的关系属于 limited relationship。即使基数显示为 1:*,也不会执行常规表扩展,见 Microsoft Learn:有限关系。
实施时还需检查以下事项:
- 两表 Col B 的数据类型、格式及空值处理是否一致,以及
dim_table3[Col B]是否确实唯一。 - 如果维度表通过导入或 DAX 计算表生成,新增 Col B 通常需要刷新后才会进入该表,不能假定它随 DirectQuery 查询同步更新。
- 使用 Power Query 合并时,确认连接器是否支持,并检查查询折叠情况;需要保留 DirectQuery 时,优先考虑数据源端视图。
- table visual 会按所选字段组合分组。如果需要区分 Table 2 中字段值完全相同的多条记录,应加入其真实明细键。
- 多对多汇总的总计通常会在总计筛选上下文中重新计算,未必等于可见各行之和,需要结合业务含义解释。
备注:内容仅供参考。
