DB2表插入报唯一约束错误,如何查找并删除重复行?
解决DB2插入时唯一约束重复报错:查找并删除重复行
第一步:定位约束对应的列
报错提示的private是约束/唯一索引名称,对应表也是private,先查询这个约束绑定的具体列:
SELECT c.COLNAME FROM SYSCAT.TABCONST tc JOIN SYSCAT.COLUMNS c ON tc.TABSCHEMA = c.TABSCHEMA AND tc.TABNAME = c.TABNAME WHERE tc.TABNAME = 'PRIVATE' AND tc.CONSTNAME = 'PRIVATE' AND tc.TYPE IN ('P', 'U'); -- 'P'代表主键约束,'U'代表唯一约束
执行后会返回触发报错的列组合,这些列的取值就是不能重复的键。
第二步:查找所有重复行
用窗口函数ROW_NUMBER()按约束列分组标记行序号,序号大于1的即为重复行:
将下面的COL_A, COL_B, COL_C替换成第一步查到的约束列:
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY COL_A, COL_B, COL_C ORDER BY (SELECT NULL)) AS RN FROM PRIVATE t QUALIFY RN > 1; -- DB2支持QUALIFY直接筛选窗口函数结果
如果你的DB2版本不支持QUALIFY,改用子查询方式:
SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER (PARTITION BY COL_A, COL_B, COL_C ORDER BY (SELECT NULL)) AS RN FROM PRIVATE t ) sub WHERE RN > 1;
这个查询会列出所有违反约束的重复行,方便你确认具体数据。
第三步:删除重复行
保留每组中的一行(示例为随机保留一行,若需按规则保留,可将ORDER BY (SELECT NULL)替换为ORDER BY 你的时间列 DESC/ASC):
WITH DUPLICATES AS ( SELECT ROWID, -- 用ROWID定位行,大表操作更高效 ROW_NUMBER() OVER (PARTITION BY COL_A, COL_B, COL_C ORDER BY (SELECT NULL)) AS RN FROM PRIVATE ) DELETE FROM PRIVATE WHERE ROWID IN (SELECT ROWID FROM DUPLICATES WHERE RN > 1);
你的原查询为何没找到重复?
你之前用COL1, COL2, COL3分组查询,但这些列并非报错中private约束对应的列,所以即使这些列无重复,约束绑定的列仍存在重复值,必须先定位约束列再进行查询。
内容的提问来源于stack exchange,提问作者noobCoder
相关产品推荐
相关产品推荐

