基于TableA填充TableB:处理UPDATE记录NULL值的SQL问题
问题分析与解决方案
场景描述
现有TableA包含以下记录:
| id | Name | Address | phone | RecordType | ProcessStatus |
|---|---|---|---|---|---|
| 1 | ABC | HYD | 123 | INSERT | 4 |
| 2 | PQR | IND | 111 | INSERT | 4 |
| 1 | ABC | NULL | 6780 | UPDATE | 3 |
需求说明
仅筛选RecordType='UPDATE'类型的记录,若该类记录存在NULL值,需匹配同ID的RecordType='INSERT'记录获取对应值填充NULL,最终生成如下结构的TableB:
| id | Name | Address | phone | RecordType | ProcessStatus |
|---|---|---|---|---|---|
| 1 | ABC | HYD | 6780 | UPDATE | 3 |
尝试的SQL及问题
本人尝试的SQL语句如下:
SELECT COALESCE(A.ID,B.ID), COALESCE(A.ADDRESS,B.ADDRESS), COALESCE(A.PHONE,B.PHONE), COALESCE(A.RECORD_TYPE,B.RECORD_TYPE), COALESCE(A.STATUS,B.STATUS) FROM #TEMP A INNER JOIN #TEMP B ON A.ID=B.ID WHERE A.RECORD_TYPE='UPDATE'
但得到的结果为:
| ID | ADDRESS | PHONE | RECORD_TYPE | STATUS |
|---|---|---|---|---|
| 1 | ABC | 123 | UPDATE | 3 |
| 1 | ABC | NULL | UPDATE | 3 |
正确的SQL实现方案
你的问题核心在于没有限定关联表B的RecordType为INSERT,同时SELECT字段和原表字段存在不匹配(比如原表是ProcessStatus,你写的STATUS)。下面给出两种可行方案:
方案一:关联限定INSERT记录 + COALESCE填充
SELECT A.id, COALESCE(A.Name, B.Name) AS Name, COALESCE(A.Address, B.Address) AS Address, COALESCE(A.phone, B.phone) AS phone, A.RecordType, A.ProcessStatus FROM #TEMP A LEFT JOIN #TEMP B ON A.id = B.id AND B.RecordType = 'INSERT' -- 只关联同ID的INSERT类型记录 WHERE A.RecordType = 'UPDATE';
逻辑说明:
- 用
LEFT JOIN保证所有UPDATE记录都能被保留(如果业务中同ID一定存在INSERT记录,用INNER JOIN也可以) - 给关联条件加上
B.RecordType = 'INSERT',避免关联到其他类型记录导致生成重复行 - 对每个可能为NULL的字段,用
COALESCE优先取UPDATE记录的值,NULL时再取INSERT记录的对应值 - 固定保留UPDATE记录的
RecordType和ProcessStatus,符合需求中最终结果的类型要求
方案二:窗口函数(适配同ID多条INSERT记录的场景)
如果同ID可能存在多条INSERT记录,我们可以用窗口函数先获取最新的INSERT记录值,再和UPDATE记录关联:
WITH InsertRecords AS ( SELECT id, Name, Address, phone, -- 按业务规则取同ID最新的INSERT记录,这里用ProcessStatus倒序示例 ROW_NUMBER() OVER (PARTITION BY id ORDER BY ProcessStatus DESC) AS rn FROM #TEMP WHERE RecordType = 'INSERT' ) SELECT A.id, COALESCE(A.Name, B.Name) AS Name, COALESCE(A.Address, B.Address) AS Address, COALESCE(A.phone, B.phone) AS phone, A.RecordType, A.ProcessStatus FROM #TEMP A LEFT JOIN InsertRecords B ON A.id = B.id AND B.rn = 1 -- 只关联每条ID的最新INSERT记录 WHERE A.RecordType = 'UPDATE';
逻辑说明:
- 先用CTE筛选出所有INSERT记录,通过窗口函数给每个ID的INSERT记录排序,取最新的一条(排序规则可根据实际业务调整,比如创建时间)
- 再和UPDATE记录关联,保证每个UPDATE记录只匹配一条INSERT记录,避免出现重复结果
验证结果
执行上述任一方案的SQL,都会得到你需要的TableB结果:
| id | Name | Address | phone | RecordType | ProcessStatus |
|---|---|---|---|---|---|
| 1 | ABC | HYD | 6780 | UPDATE | 3 |
内容的提问来源于stack exchange,提问作者Younus Mohammed
相关产品推荐
相关产品推荐

