SQL Server删除重复记录异常:执行删除语句后所有记录被删除的问题排查
问题分析与解决方法
嘿,我来帮你揪出问题所在,再给你靠谱的解决方案~
你的删除语句为什么会全删?
你写的删除语句逻辑完全跑偏啦:
DELETE FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO WHERE COD_PLANO_PAGAMENTO IN ( SELECT MAX(COD_PLANO_PAGAMENTO) COD_PLANO_PAGAMENTO FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO GROUP BY COD_PLANO_PAGAMENTO )
这里的GROUP BY COD_PLANO_PAGAMENTO意味着把同一个COD_PLANO_PAGAMENTO的所有记录归为一组,每组的MAX(COD_PLANO_PAGAMENTO)就是这个COD本身啊!所以子查询返回的是所有存在的COD_PLANO_PAGAMENTO值,DELETE的时候自然就匹配了所有记录,直接全删了。
符合需求的正确删除逻辑
你的核心需求是:每个COD_MOVIMENTO下,相同COD_PLANO_PAGAMENTO的记录只保留一条(比如删除COD_MOVIMENTO=405且COD_PLANO_PAGAMENTO=9的第二条)。所以分组维度必须是COD_MOVIMENTO + COD_PLANO_PAGAMENTO,而不是单独的COD_PLANO_PAGAMENTO。
方法1:用窗口函数(推荐,适用于大多数现代数据库:MySQL8+/SQL Server/Oracle/PostgreSQL)
先执行查询确认要删除的记录(一定要先确认!):
SELECT * FROM ( SELECT *, -- 按COD_MOVIMENTO+COD_PLANO_PAGAMENTO分组,给每组的记录编号 ROW_NUMBER() OVER ( PARTITION BY COD_MOVIMENTO, COD_PLANO_PAGAMENTO ORDER BY COD_PLANO_PAGAMENTO -- 按COD排序,保留第一条;如果要保留最后一条,改成ORDER BY COD_PLANO_PAGAMENTO DESC ) AS rn FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO ) t WHERE rn > 1 -- 编号>1的就是重复的,需要删除
确认无误后,执行删除:
MySQL 8+版本写法:
DELETE t FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY COD_MOVIMENTO, COD_PLANO_PAGAMENTO ORDER BY COD_PLANO_PAGAMENTO ) AS rn FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO ) t WHERE rn > 1
SQL Server/Oracle版本写法:
WITH CTE_Duplicates AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY COD_MOVIMENTO, COD_PLANO_PAGAMENTO ORDER BY COD_PLANO_PAGAMENTO ) AS rn FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO ) DELETE FROM CTE_Duplicates WHERE rn > 1
方法2:关联删除(适用于不支持窗口函数的老版本数据库,比如MySQL 5.x)
同样先确认要删除的记录:
SELECT t1.* FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO t1 JOIN TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO t2 ON t1.COD_MOVIMENTO = t2.COD_MOVIMENTO AND t1.COD_PLANO_PAGAMENTO = t2.COD_PLANO_PAGAMENTO AND t1.COD_PLANO_PAGAMENTO < t2.COD_PLANO_PAGAMENTO -- 保留COD更大的那条(最后一条);要保留第一条就改成>
确认后执行删除:
DELETE t1 FROM TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO t1 JOIN TB_MOVIMENTO_PDV_DETALHE_PLANO_PAGAMENTO t2 ON t1.COD_MOVIMENTO = t2.COD_MOVIMENTO AND t1.COD_PLANO_PAGAMENTO = t2.COD_PLANO_PAGAMENTO AND t1.COD_PLANO_PAGAMENTO < t2.COD_PLANO_PAGAMENTO
重要提醒
执行删除操作前,一定要先备份数据,或者先运行对应的SELECT语句确认要删除的记录完全符合预期,避免误删哦!
内容的提问来源于stack exchange,提问作者Favieri
相关产品推荐
相关产品推荐

