如何参数化UNION实现优先取TabA数据,无对应数据时取TabB
SQL需求优化方案
原数据表
TabA
| Name | qty | batchNo | tabType |
|---|---|---|---|
| X | 200 | null | A |
| X | 200 | null | A |
| X | 100 | null | A |
TabB
| Name | qty | batchNo | tabType |
|---|---|---|---|
| X | 500 | null | B |
| Y | 50 | null | B |
需求说明
获取TabB中的数据行,但如果同一Name在TabA中已有对应数据行,则仅保留TabA的相关行。
期望结果
| Name | qty | batchNo |
|---|---|---|
| X | 200 | null |
| X | 200 | null |
| X | 100 | null |
| Y | 50 | null |
现有代码问题
你当前写的SQL不仅存在语法错误(第二个NOT EXISTS子句缺少正确的表关联写法),而且逻辑嵌套复杂,需要多次扫描合并后的临时表,可读性和性能都不够理想:
With UNI as (Select * from TabA UNION ALL TabB) Select * from UNI U where (EXISTS (Select 1 from UNI B where U.name=B.name and U.tabType<>B.tabType and NVL(U.batchNo)=NVL(B.batchNo)) and U.tabType ='A') OR NOT EXISTS (SELECT 1 from UNI B where U.name=B.name and U.tabType<>B.tabType)
更优雅的实现方式
这里提供两种简洁高效的方案,直接通过UNION ALL组合目标数据,逻辑清晰且性能更优:
方案一:NOT IN筛选
SELECT Name, qty, batchNo FROM TabA UNION ALL SELECT Name, qty, batchNo FROM TabB WHERE Name NOT IN (SELECT DISTINCT Name FROM TabA);
逻辑说明:先取出TabA的全部数据,再筛选出TabB中Name从未在TabA出现过的行,两者合并即可得到目标结果,写法简洁直观。
方案二:LEFT JOIN筛选(大数据量更优)
SELECT Name, qty, batchNo FROM TabA UNION ALL SELECT b.Name, b.qty, b.batchNo FROM TabB b LEFT JOIN TabA a ON b.Name = a.Name WHERE a.Name IS NULL;
逻辑说明:通过左连接判断TabB的Name是否在TabA中存在,仅保留左连接后TabA侧无匹配的行,再和TabA全量数据合并。这种方式在数据量较大时,数据库的执行计划通常会更高效。
内容的提问来源于stack exchange,提问作者Sadam
相关产品推荐
相关产品推荐

