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。

第 5 步:全外连接 T1 和 T2

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

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

第 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 函数,将来编译时将根据数据库类型自动翻译成相应的方言。

第 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 列。

第 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

编译生成 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 的嵌套查询更加清晰可维护。

相关推荐
天天喝旺仔3 小时前
PostgreSQL 慢查询治理实战:读懂 EXPLAIN ANALYZE 执行计划,落地复合索引、部分索引与覆盖索引
sql·postgresql·性能优化·数据库开发
一个天蝎座 白勺 程序猿5 小时前
SQL Server数据库迁移实测:金仓KES V9R4C019让存量T-SQL“少量修改”
数据库·sql·kingbasees
shirsl7 小时前
数据开发每日面试题 Day 1
大数据·数据库·sql·big data
2601_960356388 小时前
消费者洞察岗项目准备清单:SQL、问卷、用户分层与可视化
大数据·数据库·sql
大牧师1 天前
TypeORM 入门教程
后端·sql·mysql·orm·nest·typeorm
RunProof可证工程1 天前
AI 写的登录接口能跑,上线前我却查出 SQL 注入写法
sql·代码规范
YangYang9YangYan1 天前
校招视角|财务数字化岗位 SQL、工具、项目完整备考指南
大数据·数据库·sql
编程_大白1 天前
IDEA配置SQL方言
java·sql·intellij-idea