表中的重复项问题是SQL中最古老的问题之一,尤其是在互联网服务的快速增长和大量数据迁移的情况下,问题愈加严重。最初,问题通过手动解决:使用一次性脚本找到重复项并删除它们,但随着数据的增长,这种方法变得低效。
问题:在不谨慎的加载、迁移或故障的情况下,常常会产生数万个具有相同关键特征(例如,电子邮件或护照)的行。这导致集成错误、不准确的分析以及客户信任度下降。
解决方案:通过分组和窗口函数构建重复项报告;实现删除重复记录,并保留一条“正确”的记录;为关键字段添加唯一约束(UNIQUE)并定期审计。
代码示例
WITH Duplicates AS ( SELECT email, COUNT(*) AS cnt FROM users GROUP BY email HAVING COUNT(*) > 1 ) SELECT u.* FROM users u JOIN Duplicates d ON u.email = d.email ORDER BY u.email, u.id;
删除重复项(保留具有最小id的行):
DELETE FROM users WHERE id NOT IN ( SELECT MIN(id) FROM users GROUP BY email );
关键特性:
可以使用DISTINCT删除表中的重复项吗?
不可以,DISTINCT仅对查询(SELECT)有效,它不会从表中删除行。需要使用DELETE或INSERT ... SELECT与DISTINCT结合创建一个新的干净表。
命令DELETE ... WHERE id NOT IN (SELECT MIN(id) ...)能够保证删除所有重复项吗?
不可以,如果关键列中有NULL,这种查询可能会错误地保留重复项,因为NULL值比较的特性。
仅创建UNIQUE INDEX就足够确保以后不会有重复项吗?
不可以,该索引只会防止新的重复项插入,但不会影响表中已经存在的重复项。
CRM系统从不同来源复制用户时未考虑电子邮件的唯一性,数据库中有50000个重复项。大量添加UNIQUE索引导致服务故障,系统停机。
优点:
缺点:
工程师定期通过专业报告分析重复项,清理数据库,创建唯一索引。在迁移新数据之前进行验证。
优点:
缺点: