SQL实现Table1整行无重复数据识别并迁移至Table2的方法
整行去重跨表同步SQL实现方案
原SQL存在两个问题:一是仅通过DeliveryOrder单字段判断重复,无法识别同单号不同其他字段的新记录;二是插入字段列表遗漏了DO字段,会导致目标表该字段值异常。
整行去重的核心逻辑是在重复判断时关联所有业务字段的匹配关系,只有全部字段值完全一致时才判定为重复记录,以下是可直接使用的实现:
基础通用实现(兼容所有主流关系型数据库)
INSERT INTO Table2 (Batch, DeliveryOrder, DO) SELECT t1.Batch, t1.DeliveryOrder, t1.DO FROM Table1 t1 WHERE NOT EXISTS ( SELECT 1 FROM Table2 t2 WHERE t2.Batch = t1.Batch AND t2.DeliveryOrder = t1.DeliveryOrder AND t2.DO = t1.DO );
逻辑说明
- 子查询中对三个业务字段全部做等值匹配,仅当三个字段的组合完全重合时,才判定记录已存在,跳过插入;只要任意一个字段值不同,就会作为新记录写入Table2,完全满足整行去重要求
- 子查询使用
SELECT 1替代具体字段查询,仅做存在性判断,执行效率更高
场景适配优化
1. 字段允许NULL值的场景
普通等值运算符=无法判断NULL值的相等性(NULL与任何值做=比较返回结果都为未知,会导致NULL值组合的重复记录被重复插入),需要使用数据库对应的空值安全比较符:
- MySQL场景使用安全等于运算符
<=>:
WHERE t2.Batch <=> t1.Batch AND t2.DeliveryOrder <=> t1.DeliveryOrder AND t2.DO <=> t1.DO
- PostgreSQL、SQL Server等支持ANSI SQL的场景使用
IS NOT DISTINCT FROM:
WHERE t2.Batch IS NOT DISTINCT FROM t1.Batch AND t2.DeliveryOrder IS NOT DISTINCT FROM t1.DeliveryOrder AND t2.DO IS NOT DISTINCT FROM t1.DO
2. 大数据量性能优化
如果两张表数据量较大,建议在Table2上为三个业务字段建立联合索引,避免去重判断时全表扫描,大幅提升同步效率:
-- 通用联合索引语法,适配绝大多数数据库 CREATE INDEX idx_t2_biz_fields ON Table2 (Batch, DeliveryOrder, DO);
3. 支持EXCEPT语法的数据库简化写法
PostgreSQL、SQL Server、BigQuery等支持集合差集运算的数据库,可以直接用EXCEPT实现等价逻辑,不需要手动写全字段匹配条件,字段较多时写法更简洁:
INSERT INTO Table2 (Batch, DeliveryOrder, DO) SELECT Batch, DeliveryOrder, DO FROM Table1 EXCEPT SELECT Batch, DeliveryOrder, DO FROM Table2;
注意:
EXCEPT会自动对差集结果去重,如果Table1内部本身存在完全重复的多行记录、需要全部保留同步到Table2,请改用EXCEPT ALL。
内容的提问来源于stack exchange,提问作者Asher Crush
相关产品推荐
相关产品推荐

