SQLazy:多表按 ID 合并为单行

问题描述

将多个结构相似但列名不同的表按 ID 全外连接合并为宽表。4 个表结构类似,每个表 2 个字段,字段含义相同但名字不同(id、id2、id3、id4 都是 ID)。现在要将 4 个表按 ID 合并为单行,每个 ID 唯一一行,当 ID 不在某个表中时对应列取 NULL。

源数据

T1 table:

id

colA

555

A_OK

T2 table:

id2

colB

555

B_OK

10

Bx

T3 table:

id3

colC

222

C

T4 table:

id4

colD

10

Dx

期望结果

ID_main

id

colA

id2

colB

id3

colC

id4

colD

10



10

Bx



10

Dx

222





222

C



555

555

A_OK

555

B_OK





比如,ID=555 在 T1 和 T2 中都有记录,T3 和 T4 中没有,因此 id、colA、id2、colB 有值,id3/colC/id4/colD 为 NULL。

ID=222 只在 T3 中有记录,其他表都没有,因此只有 id3、colC 有值,其余均为 NULL。

ID=10 在 T2 和 T4 中有记录,T1 和 T3 中没有,因此 id2、colB、id4、colD 有值,其余为 NULL。

SQLazy 分步实现

核心思路:先用 derive 将各表的 ID 列统一命名为 ID_main,方便后续合并。然后从第一个表开始,逐表进行全外连接:每次用 join 将当前结果与下一个表按 ID_main 全外连接,再用 derive 和 nvl 函数将新增 ID 合并到 ID_main 列,如此逐表追加获得结果。

Name

Anchor

Statement

t1

T1

derive id as ID_main, id, colA

t2

T2

derive id2 as ID_main, id2, colB

t3

T3

derive id3 as ID_main, id3, colC

t4

T4

derive id4 as ID_main, id4, colD

r1

t1

join ID_main; with t2; ID_main; take id2, colB; full

r1b


derive nvl(ID_main, id2) as ID_main, id, colA, id2, colB

r2


join ID_main; with t3; ID_main; take id3, colC; full

r2b


derive nvl(ID_main, id3) as ID_main, id, colA, id2, colB, id3, colC

r3


join ID_main; with t4; ID_main; take id4, colD; full



derive nvl(ID_main, id4) as ID_main, id, colA, id2, colB, id3, colC, id4, colD

【点击在线运行本例】

下面逐一解释这些步骤。

第 1–4 步:统一各表的 ID 列名

derive id as ID_main, id, colA

对 T1–T4 分别用 derive 将各自不同的 ID 列名(id/id2/id3/id4)统一重命名为 ID_main。

Picture1png

第 5 步:全外连接 T1 和 T2

join ID_main; with t2; ID_main; take id2, colB; full

用 join 功能将 t1 与 t2 按 ID_main 进行全外连接。

Picture2png

第 6 步:合并 ID 列中的 NULL

derive nvl(ID_main, id2) as ID_main, id, colA, id2, colB

如果某条记录来自 t2 而 t1 中没有,则这条记录的 ID_main 为 NULL,这一步将把这种记录中的 ID_main 赋值为 t2.id2,从而确保 ID_main 列始终有值。不同的 SQL 实现本步骤时方言不同,比如 oracle 用 nvl,SQLServer 用 COALESCE,而 NSPL 统一使用 nvl 函数,将来编译时将根据数据库类型自动翻译成相应的方言。

Picture3png

第 7–8 步:重复追加 T3

join ID_main; with t3; ID_main; take id3, colC; full

derive nvl(ID_main, id3) as ID_main, id, colA, id2, colB, id3, colC

重复 join + derive 模式,将 T3 全外连接到当前结果中。每次追加一个表后,用 ifn 将新增的 ID 合并到统一的 ID_main 列。

Picture4png

第 9-10 步:重复追加 T4,得到最终结果

join ID_main; with t4; ID_main; take id4, colD; full

derive nvl(ID_main, id4) as ID_main, id, colA, id2, colB, id3, colC, id4, colD

Picture5png

编译生成 SQL

确认上述步骤后,SQLazy 编译器自动生成原生 SQL(SQL Server 语法):

WITH t1 AS (
		SELECT id AS ID_main, id, colA
		FROM T1
	),
	t2 AS (
		SELECT id2 AS ID_main, id2, colB
		FROM T2
	),
	r1 AS (
		SELECT t1.ID_main, t1.id, t1.colA, t2.id2, t2.colB
		FROM t1
			FULL JOIN t2 ON ID_main = t2.ID_main
	),
	r1b AS (
		SELECT COALESCE(NULLIF(CAST(ID_main AS VARCHAR(10)), ''), NULLIF(CAST(id2 AS VARCHAR(10)), '')) AS ID_main
			, id, colA, id2, colB
		FROM r1
	),
	t3 AS (
		SELECT id3 AS ID_main, id3, colC
		FROM T3
	),
	r2 AS (
		SELECT r1b.ID_main, r1b.id, r1b.colA, r1b.id2, r1b.colB
			, t3.id3, t3.colC
		FROM r1b
			FULL JOIN t3 ON ID_main = t3.ID_main
	),
	r2b AS (
		SELECT COALESCE(NULLIF(CAST(ID_main AS VARCHAR(10)), ''), NULLIF(CAST(id3 AS VARCHAR(10)), '')) AS ID_main
			, id, colA, id2, colB, id3
			, colC
		FROM r2
	),
	t4 AS (
		SELECT id4 AS ID_main, id4, colD
		FROM T4
	),
	r3 AS (
		SELECT r2b.ID_main, r2b.id, r2b.colA, r2b.id2, r2b.colB
			, r2b.id3, r2b.colC, t4.id4, t4.colD
		FROM r2b
			FULL JOIN t4 ON ID_main = t4.ID_main
	)
SELECT COALESCE(NULLIF(CAST(ID_main AS VARCHAR(10)), ''), NULLIF(CAST(id4 AS VARCHAR(10)), '')) AS ID_main
	, id, colA, id2, colB, id3
	, colC, id4, colD
FROM r3

SQLazy 让你用业务语言描述逻辑,而不是用 SQL 语法写嵌套查询。SQLazy 的分步计算将多表合并拆解为统一列名、逐表全外连接、合并 ID 等多个独立步骤,每一步都可以独立验证中间结果。join 功能配合 derive 和 nvl 函数,可以灵活地处理合并后的数据,如重命名列、合并 NULL 值等。这种逐个追加表的策略比 SQL 中编写多个 FULL JOIN + COALESCE 的嵌套查询更加清晰可维护。

官方链接

SQLazy 在线体验sqlazy.com(免费,无需注册)
SQLazy 项目仓库github.com/SPLWare/SQLazy