一段时间后,大多数应用程序可能由于bug而出现重复行,这不仅影响用户体验,还增加了存储需求并降低数据库性能。可以通过一个 SQL 查询来完成整个清理过程,从而有效解决这一问题。
使用范例
-- 创建表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
-- 插入数据,包括重复数据
INSERT INTO users (name, email) VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Alice', 'alice@example.com'), -- 重复数据
('Charlie', 'charlie@example.com'),
('Bob', 'bob@example.com'); -- 重复数据
巧用 CTE 公共表达式删除 MySQL 重复数据
WITH duplicates AS (
SELECT id, ROW_NUMBER() OVER(
PARTITION BY name, email
ORDER BY id DESC
) AS rownum
FROM users
)
DELETE users
FROM users
JOIN duplicates USING(id)
WHERE duplicates.rownum > 1;
输出结果:
mysql> select * from users;
+----+---------+---------------------+
| id | name | email |
+----+---------+---------------------+
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
| 3 | Alice | alice@example.com |
| 4 | Charlie | charlie@example.com |
| 5 | Bob | bob@example.com |
+----+---------+---------------------+
5 rows in set (0.00 sec)
mysql> WITH duplicates AS (
-> SELECT id, ROW_NUMBER() OVER(
-> PARTITION BY name, email
-> ORDER BY id DESC
-> ) AS rownum
-> FROM users
-> )
-> DELETE users
-> FROM users
-> JOIN duplicates USING(id)
-> WHERE duplicates.rownum > 1;
Query OK, 2 rows affected (0.00 sec)
mysql> select * from users;
+----+---------+---------------------+
| id | name | email |
+----+---------+---------------------+
| 3 | Alice | alice@example.com |
| 4 | Charlie | charlie@example.com |
| 5 | Bob | bob@example.com |
+----+---------+---------------------+
3 rows in set (0.00 sec)
解读:
这个SQL语句可以分为两个主要部分
1)WITH子句(公共表表达式,CTE):
这部分创建了一个名为duplicates
的临时结果集。它对users
表进行操作:
- 使用
PARTITION BY name, email
对名字和邮箱相同的记录进行分组。 - 在每个分组内,使用
ORDER BY id DESC
按id降序排序。 - 为每条记录分配一个
rownum
,这个数字在每个分组内从1开始计数。
2)DELETE语句:
这部分执行实际的删除操作:
- 它将
users
表与我们刚刚创建的duplicates
结果集进行JOIN。 - 删除条件是
WHERE duplicates.rownum > 1
,意味着它会删除每组重复记录中除了第一条(rownum = 1
)之外的所有记录。
需要注意的是,这个DELETE语句的语法可能不被所有数据库系统支持。例如,在MySQL中这是有效的语法,但在其他一些数据库系统中可能需要稍作调整。
总的来说,这个查询的目的是:
- 找出
users
表中名字和邮箱相同的记录。 - 对于每组重复记录,保留id最大的那一条(因为是按id降序排序)。
- 删除其他所有重复记录。
这种方法可以有效地清理数据库中的重复用户记录,同时保留每组重复记录中最新的(假设id越大越新)一条记录。