SQL删除表中重复记录方法总结

在 SQL 中删除表中的重复记录是一个常见的数据清洗操作。由于不同数据库系统(如 MySQL、PostgreSQL、SQL Server、Oracle 等)语法略有差异,下面我会以通用方法为主,并针对常见数据库给出具体示例。

一、通用思路要删除重复记录,通常需要:

识别重复行(基于一个或多个字段)保留其中一行(通常是最早插入的或具有最小/最大主键的那一行)删除其余重复行二、方法分类与示例方法1:使用窗口函数(推荐,适用于支持窗口函数的数据库)示例表结构代码语言:sql复制CREATE TABLE employees (

id INT PRIMARY KEY,

name VARCHAR(50),

email VARCHAR(100)

);插入一些重复数据:

代码语言:sql复制INSERT INTO employees VALUES

(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'); -- 重复删除重复(保留最小 id 的记录)代码语言:sql复制-- PostgreSQL / SQL Server / Oracle / MySQL 8.0+

DELETE FROM employees

WHERE id NOT IN (

SELECT MIN(id)

FROM employees

GROUP BY name, email

);或者使用窗口函数(更高效):

代码语言:sql复制-- 使用 CTE + ROW_NUMBER()

WITH duplicates AS (

SELECT id,

ROW_NUMBER() OVER (PARTITION BY name, email ORDER BY id) AS rn

FROM employees

)

DELETE FROM employees

WHERE id IN (

SELECT id FROM duplicates WHERE rn > 1

);注意:MySQL 早期版本(<8.0)不支持在 DELETE 中直接引用自身表的子查询,需用临时表绕过。

方法2:自连接删除(适用于 MySQL < 8.0)代码语言:sql复制-- 删除重复,保留较小 id 的记录

DELETE e1 FROM employees e1

INNER JOIN employees e2

WHERE e1.id > e2.id

AND e1.name = e2.name

AND e1.email = e2.email;此语法仅适用于 MySQL(使用别名进行自连接删除)。

方法3:创建新表(通用但耗资源)适用于任何数据库,适合一次性清理大量重复数据:

代码语言:sql复制-- 1. 创建无重复的新表

CREATE TABLE employees_clean AS

SELECT MIN(id) AS id, name, email

FROM employees

GROUP BY name, email;

-- 2. 删除原表并重命名(或 TRUNCATE + INSERT)

DROP TABLE employees;

ALTER TABLE employees_clean RENAME TO employees;注意:此方法会丢失原表的索引、约束等,需重新创建。

方法4:使用 EXISTS(通用)代码语言:sql复制DELETE FROM employees e1

WHERE EXISTS (

SELECT 1

FROM employees e2

WHERE e2.name = e1.name

AND e2.email = e1.email

AND e2.id < e1.id

);此写法在 PostgreSQL、SQL Server、Oracle 中有效;MySQL 需加别名或改写。

三、不同数据库注意事项数据库

是否支持 ROW_NUMBER()

自连接删除语法

子查询限制

MySQL 8.0+

较少

MySQL <8.0

✅(特殊语法)

不能直接删自己

PostgreSQL

支持

SQL Server

支持

Oracle

支持

SQLite

✅(3.25+)

❌(不支持多表 DELETE)

需用临时表

SQLite 示例(只能通过重建表):CREATE TABLE employees_new AS

SELECT MIN(id) AS id, name, email

FROM employees

GROUP BY name, email;DROP TABLE employees;

ALTER TABLE employees_new RENAME TO employees;

四、小结:最佳实践建议有主键/唯一ID:优先用 ROW_NUMBER() 或 MIN(id) 分组保留。无主键:先加临时 ID 列,再去重。大数据量:考虑分批删除,避免锁表或事务过大。生产环境:先备份,再执行删除!

[an error occurred while processing the directive]