PAYATHON 2026

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:

  1. 添加 Table 1[Col A]。
  2. 添加需要展示的 Table 2 字段,例如 Table 2[Status]。
  3. 添加 [Matched Rows]。
  4. 在该 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 中字段值完全相同的多条记录,应加入其真实明细键。
  • 多对多汇总的总计通常会在总计筛选上下文中重新计算,未必等于可见各行之和,需要结合业务含义解释。

备注:内容仅供参考。