如何关联字段近似的两张表并在字段差异处返回NULL
问题需求
需要关联两张结构一致的表(Table A 和 Table B),以NAME作为唯一关联字段,要求:
- 每个
NAME仅返回一条记录 - 除
NAME外的其他字段,若两张表中对应值一致则保留,若不一致则返回NULL
示例数据
Table A
| NAME | CITY | AGE |
|---|---|---|
| Lucas | Dallas | 21 |
| John | Chicago | 30 |
| Tim | London | 15 |
Table B
| NAME | CITY | AGE |
|---|---|---|
| Lucas | Dallas | 21 |
| John | Chicago | 45 |
| Tim | London | 15 |
错误尝试结果
使用LEFT JOIN后返回重复记录,无法实现差异字段置空需求:
| NAME | CITY | AGE |
|---|---|---|
| John | Chicago | 30 |
| John | Chicago | 45 |
解决方案
1. 已知字段名的静态SQL实现
若明确字段列表,可对每个字段使用NULLIF函数(比较两个值,相等返回原值,不等返回NULL),结合INNER JOIN实现:
SELECT a.NAME, NULLIF(a.CITY, b.CITY) AS CITY, NULLIF(a.AGE, b.AGE) AS AGE FROM TableA a INNER JOIN TableB b ON a.NAME = b.NAME;
执行结果符合需求:
| NAME | CITY | AGE |
|---|---|---|
| Lucas | Dallas | 21 |
| John | Chicago | NULL |
| Tim | London | 15 |
2. 未知字段名的动态SQL实现
若字段数量多且无法提前知晓,可通过动态生成SQL语句适配所有字段:
MySQL/MariaDB
SET @sql = ( SELECT GROUP_CONCAT( 'NULLIF(a.', column_name, ', b.', column_name, ') AS ', column_name SEPARATOR ', ' ) FROM information_schema.columns WHERE table_name = 'TableA' AND column_name != 'NAME' ); SET @sql = CONCAT( 'SELECT a.NAME, ', @sql, ' FROM TableA a INNER JOIN TableB b ON a.NAME = b.NAME' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
PostgreSQL
DO $$ DECLARE cols text; BEGIN SELECT string_agg( 'NULLIF(a.' || quote_ident(column_name) || ', b.' || quote_ident(column_name) || ') AS ' || quote_ident(column_name), ', ' ) INTO cols FROM information_schema.columns WHERE table_name = 'tablea' AND column_name != 'name'; EXECUTE format( 'SELECT a.name, %s FROM tablea a INNER JOIN tableb b ON a.name = b.name', cols ); END $$;
SQL Server
DECLARE @cols NVARCHAR(MAX); DECLARE @sql NVARCHAR(MAX); SELECT @cols = STRING_AGG( 'NULLIF(a.' + QUOTENAME(COLUMN_NAME) + ', b.' + QUOTENAME(COLUMN_NAME) + ') AS ' + QUOTENAME(COLUMN_NAME), ', ' ) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TableA' AND COLUMN_NAME != 'NAME'; SET @sql = N'SELECT a.NAME, ' + @cols + N' FROM TableA a INNER JOIN TableB b ON a.NAME = b.NAME'; EXEC sp_executesql @sql;
动态SQL会自动读取表的字段列表(排除NAME),生成通用的差异字段置空逻辑。
内容的提问来源于stack exchange,提问作者Cristina Biagiotti
相关产品推荐
相关产品推荐

