MySQL 5.7删除重复数据报错1093的原因及解决方法问询
我来帮你搞定这个问题~首先得说清楚为什么会报这个错:
这个1093错误的核心原因是MySQL 5.7的查询机制限制——当你在DELETE语句的WHERE子句里直接引用了要删除数据的目标表(也就是wallet_consume_record)作为子查询的数据源时,MySQL会认为这种操作可能引发数据一致性冲突(比如子查询还在读取表数据的时候,主DELETE已经在修改同一张表),所以直接禁止了这种写法。你之前尝试的SET optimizer_switch = 'derived_merge=off'没生效,大概率是因为这个开关主要影响派生表的合并逻辑,但对于这种直接引用目标表的子查询,底层限制依然存在。
接下来给你几个靠谱的解决办法,按推荐程度排序:
方法一:用JOIN关联删除(最推荐,性能最优)
思路是先找出每个重复trans_no对应的最小id(也就是我们要保留的那条记录),然后通过JOIN把原表和这个结果关联,只删除那些id不在保留集合里的重复行。SQL语句如下:
DELETE wcr FROM wallet_consume_record wcr JOIN ( SELECT trans_no, MIN(id) AS min_id FROM wallet_consume_record GROUP BY trans_no HAVING COUNT(trans_no) > 1 ) AS dup ON wcr.trans_no = dup.trans_no WHERE wcr.id != dup.min_id;
这种写法完全避开了在WHERE子句直接引用目标表的问题,而且JOIN的执行效率比嵌套子查询更高,适合数据量较大的表。
方法二:用临时表存储需保留的ID
如果JOIN的写法你觉得不好理解,可以先把需要保留的记录ID存到临时表,再删除不在这个表里的重复行:
-- 创建临时表,存储每个重复trans_no对应的最小id(要保留的记录) CREATE TEMPORARY TABLE tmp_keep_ids ( min_id INT PRIMARY KEY ); -- 把要保留的ID插入临时表 INSERT INTO tmp_keep_ids SELECT MIN(id) FROM wallet_consume_record GROUP BY trans_no HAVING COUNT(trans_no) > 1; -- 删除重复数据:只删trans_no重复且id不在保留列表里的行 DELETE FROM wallet_consume_record WHERE trans_no IN ( SELECT trans_no FROM wallet_consume_record GROUP BY trans_no HAVING COUNT(trans_no) > 1 ) AND id NOT IN (SELECT min_id FROM tmp_keep_ids); -- 临时表会在会话结束后自动销毁,也可以手动删掉 DROP TEMPORARY TABLE tmp_keep_ids;
因为临时表和原表是完全独立的,MySQL不会再限制子查询引用原表,这种方式逻辑更直观,适合新手理解。
方法三:嵌套两层子查询(绕开限制)
你之前尝试过嵌套子查询但没生效?可能是没套对层数。把原来的子查询再包一层,给内层子查询加个别名,让MySQL把它当成独立的派生表处理,就能绕过限制:
DELETE FROM wallet_consume_record WHERE trans_no IN ( SELECT trans_no FROM ( SELECT trans_no FROM wallet_consume_record GROUP BY trans_no HAVING COUNT(trans_no) > 1 ) AS t1 ) AND id NOT IN ( SELECT min_id FROM ( SELECT MIN(id) AS min_id FROM wallet_consume_record GROUP BY trans_no HAVING COUNT(trans_no) > 1 ) AS t2 );
这里的关键是给内层子查询加上t1、t2这样的别名,让MySQL不再认为子查询是直接引用目标表,而是处理一个独立的派生表结果。
内容的提问来源于stack exchange,提问作者Dolphin

