MySQL中删除无唯一标识符的表内重复数据
MySQL中删除无唯一标识符的表内重复数据
嘿,我懂你现在的困扰——用MySQL Workbench 8.0.36学SQL的时候,发现Employee表里有重复数据,就像EmpID=1的Arjun,信息被录入了两次,而且原表还没有唯一标识符来区分这些重复行(你提到的RowNum只是临时用的,原表没有这个字段)。先把你的表结构和数据明确一下(去掉临时的RowNum):
| EmpID | Empname | Gender | Salary | City |
|---|---|---|---|---|
| 1 | Arjun | M | 75000 | Pune |
| 1 | Arjun | M | 75000 | Pune |
| 2 | Ekadanta | M | 125000 | Bangalore |
| 3 | Lalita | F | 150000 | Mathura |
| 4 | Madhav | M | 250000 | Delhi |
| 5 | Vishakha | F | 120000 | Mathura |
针对这种没有唯一主键的重复数据删除,因为你用的是MySQL 8.0+版本,我推荐两种实用的方法:
方法一:用窗口函数标记重复行(最稳妥)
MySQL 8.0开始支持窗口函数,我们可以用ROW_NUMBER()给每组重复数据分配行号,然后删除行号大于1的记录(只保留每组的第一条):
-- 先创建一个临时的带行号的数据集 WITH ranked_employees AS ( SELECT *, -- 按所有字段分组,标记重复行的序号 ROW_NUMBER() OVER (PARTITION BY EmpID, Empname, Gender, Salary, City ORDER BY (SELECT NULL)) AS rn FROM Employee ) -- 删除行号大于1的重复记录 DELETE FROM Employee WHERE (EmpID, Empname, Gender, Salary, City) IN ( SELECT EmpID, Empname, Gender, Salary, City FROM ranked_employees WHERE rn > 1 );
这里解释下:
PARTITION BY后面的字段是判断重复的依据——只要这些字段完全相同,就视为重复行ORDER BY (SELECT NULL)是因为我们不需要特意保留某一条(比如最早/最晚录入的),如果有时间戳之类的字段,可以换成那个字段来指定保留哪条
方法二:用自连接删除重复行
如果你不想用CTE(公共表表达式),也可以通过自连接的方式,利用MySQL隐式的ROWID来区分不同行:
DELETE e1 FROM Employee e1 JOIN Employee e2 -- 匹配所有重复字段 ON e1.EmpID = e2.EmpID AND e1.Empname = e2.Empname AND e1.Gender = e2.Gender AND e1.Salary = e2.Salary AND e1.City = e2.City -- 保留ROWID更小的那条,删除更大的 AND e1.ROWID > e2.ROWID;
注意:ROWID是MySQL内部的行标识符,不同存储引擎(比如InnoDB/MyISAM)的实现可能有差异,所以方法一更通用。
后续预防建议
为了避免以后再出现这种重复数据,最好给表加上唯一约束或者主键:
-- 如果EmpID应该是唯一的,直接设为主键 ALTER TABLE Employee ADD PRIMARY KEY (EmpID); -- 如果EmpID可能重复(比如同个员工多条记录),可以创建复合唯一索引 CREATE UNIQUE INDEX idx_employee_unique ON Employee (EmpID, Empname, Gender, Salary, City);
备注:内容来源于stack exchange,提问作者Rakesh Singh
相关产品推荐
相关产品推荐

