数据仓库图解交互式教材
SQL 与数据加工Join 为什么会让金额变大?
学习进度0 / 64
EN
首页课程学习Join 为什么会让金额变大?
4-3SQL 与数据加工10 分钟

Join 为什么会让金额变大?

先用一个账户的三条介质记录看清一对多,再用 2 × 2 例子检查两边 key 都不唯一的结果,最后回到时点余额核对目标日期、右表基数和金额。

Join数据粒度金额对账
SQL 没报错,A001 的余额为什么从 100,000 变成 300,000?

Join 为什么会让金额变大?

两张表都有 account_id,不代表它们可以直接横向拼接。先数左右两边每个 key 有几行,再看 Join 后一行还代表什么。

左表1 行A001 × 2026-09-30
右表3 行A001 的账户介质
错误结果3 倍100,000 被复制成 300,000

有时最好的 Join 是不 Join:先确认这张辅助表是否真的属于当前指标的统计粒度。

核心概念

Join 放大

当 JOIN key 在一侧或两侧并不唯一时,同一行会被复制到多次匹配结果中。若没有回到目标数据粒度就直接求和,金额会随匹配行数一起放大。

先看两张表各自的一行

DWD 中 A001 的一行代表“账户 A001 在 2026-09-30 的余额”。AccountMedium 中的三行分别代表一个账户介质:CARD、CARD、PASSBOOK。两张表都出现 account_id,但一行代表的事情不同。

直接 Join 后,A001 的余额字段被复制到三行。数据库只完成了关系运算,并不知道 balance 不应该按账户介质重复计算。

  • 左表:1 行 = 账户 × 快照日,A001 的 balance = 100,000。
  • 右表:1 行 = 账户 × 账户介质,A001 有 3 行。
  • Join 后:A001 的 1 行 × 3 行介质 = 3 行;直接 SUM(balance) 会得到 300,000,但 A001 只应计一次 100,000。
M:N 分步实验 · 两边 key 都不唯一

把 2 × 2 = 4 一步步走完

一对多已经会复制度量;如果 JOIN key 两边都不唯一,结果还会继续放大。下面用一组最小的 2 × 2 数据,把匹配、放大、根因和修复拆成 6 步。

正在加载交互实验…

余额快照要限定目标日期

余额快照的一行代表“账户 × 快照日”。若 A001 的多个日期都进入 JOIN,即使 AccountMedium 每个账户只有一行,结果也会同时包含多个时点的余额,不能直接当作某一天的账户余额相加。

AccountMedium 还可能在同一个 account_id 下有多行介质记录。过滤左表快照日会改变参与匹配的日期行,右表预聚合会改变每个 key 的匹配基数;两项处理针对不同原因。

多日期快照 · 逐 key 核对

日期过滤和右表预聚合各自改变什么?

调整账户数量、快照天数和账户介质行数,逐 key 查看匹配对数、输出行、结果粒度与余额差额。分别切换目标日期过滤、右表按 account_id 预聚合与 LEFT/INNER JOIN,再比较四种修复组合和未匹配账户的处理结果。

正在加载交互实验…

修复方式取决于目标 Grain

本例的目标粒度(Grain)是“每个账户在目标快照日一行”,所以要过滤其他日期,并将 AccountMedium 收敛到 account_id 一行。左表跨多个日期、右表同一账户有多行时,只做其中一项,另一处的行数问题仍然存在。

如果指标要按每种介质输出,账户级预聚合会把这些记录合并成一行,无法再按介质分组;这时应重新定义输出粒度与度量口径。若右表信息不影响指标,也可以不连接这张辅助表。