MySQL删除重复记录保留最小ID的SQL语句失效问题咨询
问题分析与修正方案
你的SQL存在的核心问题
你写的删除语句里,第二个子查询犯了一个明显的逻辑错误:
select login_name from (select min(id) from admin_sync_user group by login_name having count(login_name) > 1) as b
内层子查询返回的是每个重复login_name对应的最小id值,但外层却试图去选login_name字段——这个字段根本不存在于内层查询的结果里!这就导致id not in (...)这个条件的集合是空的,相当于这个过滤条件完全没生效,MySQL只会执行前半部分的login_name in (...),把所有有重复login_name的记录全删掉了,而不是保留最小id的那条。
修正后的SQL写法
方法1:修复你原来的SQL结构
把第二个子查询的字段逻辑改对,让它返回正确的最小id集合:
delete from admin_sync_user where login_name in ( select login_name from ( select login_name from admin_sync_user group by login_name having count(login_name) > 1 ) as a ) and id not in ( select min_id from ( select min(id) as min_id from admin_sync_user group by login_name having count(login_name) > 1 ) as b );
这里给内层的min(id)起了别名min_id,外层直接获取这些最小id,这样id not in (...)就能正确过滤掉需要保留的记录。
方法2:更高效的自连接写法(推荐)
这种写法逻辑更直观,性能也更好:
delete t1 from admin_sync_user t1 join admin_sync_user t2 on t1.login_name = t2.login_name and t1.id > t2.id;
它的逻辑是:找到所有和其他记录login_name相同,但id更大的记录,直接删除这些大id的记录,自动保留每个login_name对应的最小id条目。
方法3:MySQL 8.0+ 用窗口函数(最清晰)
如果你的MySQL版本是8.0及以上,用窗口函数可以更直白地标记重复记录:
delete from admin_sync_user where id in ( select id from ( select id, row_number() over (partition by login_name order by id asc) as rn from admin_sync_user ) as t where rn > 1 );
row_number()会给每个login_name分组的记录按id升序编号,rn=1就是要保留的最小id记录,rn>1的就是需要删除的重复项。
内容的提问来源于stack exchange,提问作者kate
相关产品推荐
相关产品推荐

