PAYATHON 2026

SQL Server 根据 custId 合并多个表的数据

支付阿杰

结论

不需要连接三个表。用 UNION ALL 把各表中同一客户的数据合并成多行即可。每个查询分支返回相同的列,并用固定值标明数据来源。

例如:

  • col1 = 1:来自 Customer
  • col1 = 2:来自 Payment
  • col1 = 3:来自 Refund

查询示例

下面的查询返回 custId = 3 的客户资料、付款备注和退款备注:

DECLARE @CustId int = 3;

SELECT
    c.CustId,
    c.Notes,
    1 AS col1
FROM Customer AS c
WHERE c.CustId = @CustId

UNION ALL

SELECT
    p.custId,
    p.PmtNotes,
    2 AS col1
FROM Payment AS p
WHERE p.custId = @CustId
  AND p.PmtNotes IS NOT NULL

UNION ALL

SELECT
    r.custId,
    r.refNotes,
    3 AS col1
FROM Refund AS r
WHERE r.custId = @CustId
  AND r.refNotes IS NOT NULL

ORDER BY col1;

根据题目中的示例数据,查询结果是:

CustIdNotescol1
3gg1
3jj3

Payment 表中 custId = 3 对应的 PmtNotes 为 NULL,所以被 PmtNotes IS NOT NULL 条件排除了。如果想保留这条记录,删除该条件即可。结果中会增加一行:

CustIdNotescol1
3NULL2

为什么使用 UNION ALL

这里要把不同表中的备注合并成多行,而不是连接到同一行,因此用 UNION ALL 更合适。

三个查询分支返回的内容都是:

客户编号、备注、来源标识

原始列名虽然分别是 Notes、PmtNotes 和 refNotes,但这些列在各个查询中处于相同位置。合并后的结果会采用第一个查询指定的列名 Notes。

这里应使用 UNION ALL,不建议直接使用 UNION。UNION 会执行额外的去重操作,可能删掉原本有效的重复记录,也会带来不必要的处理开销。

如果只需要 Customer 和 Refund

如果不需要付款记录,只合并两个表即可:

DECLARE @CustId int = 3;

SELECT
    c.CustId,
    c.Notes,
    1 AS col1
FROM Customer AS c
WHERE c.CustId = @CustId

UNION ALL

SELECT
    r.custId,
    r.refNotes,
    3 AS col1
FROM Refund AS r
WHERE r.custId = @CustId
  AND r.refNotes IS NOT NULL

ORDER BY col1;

这段查询会返回题目所示的两行结果。

返回更清晰的来源名称

数字标识便于程序处理,但人工查看时不够直观。可以在结果中同时返回来源名称:

DECLARE @CustId int = 3;

SELECT
    c.CustId,
    c.Notes,
    1 AS SourceId,
    CAST('Customer' AS varchar(20)) AS SourceName
FROM Customer AS c
WHERE c.CustId = @CustId

UNION ALL

SELECT
    p.custId,
    p.PmtNotes,
    2 AS SourceId,
    CAST('Payment' AS varchar(20)) AS SourceName
FROM Payment AS p
WHERE p.custId = @CustId
  AND p.PmtNotes IS NOT NULL

UNION ALL

SELECT
    r.custId,
    r.refNotes,
    3 AS SourceId,
    CAST('Refund' AS varchar(20)) AS SourceName
FROM Refund AS r
WHERE r.custId = @CustId
  AND r.refNotes IS NOT NULL

ORDER BY SourceId;

注意事项

参与 UNION ALL 的每个 SELECT 都必须满足以下条件:

  1. 返回的列数相同。
  2. 对应位置的列使用相同或兼容的数据类型。

Notes、PmtNotes 和 refNotes 最好使用兼容的字符类型,例如都使用 nvarchar,长度也应相容。如果这些列的数据类型或排序规则不同,可能需要显式转换:

CAST(p.PmtNotes AS nvarchar(500))

数据量较大时,还要检查三个表的客户编号列是否有合适的索引。Customer.CustId 通常应设为主键,Payment.custId 和 Refund.custId 则可以建立普通索引,以提高按客户编号筛选的效率。

备注:内容仅供参考。