删除 MySQL 中的重复行

Posted

技术标签:

【中文标题】删除 MySQL 中的重复行【英文标题】:Remove duplicate rows in MySQL 【发布时间】:2011-03-19 17:18:33 【问题描述】:

我有一个包含以下字段的表格:

id (Unique)
url (Unique)
title
company
site_id

现在,我需要删除具有相同 title, company and site_id 的行。一种方法是使用以下 SQL 和脚本 (php):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

运行此查询后,我可以使用服务器端脚本删除重复项。

但是,我想知道这是否只能使用 SQL 查询来完成。

【问题讨论】:

快速提问:是否总是希望不存在重复的(title、company、site_id)?如果是这样,我会在数据库中设置一个约束来强制 title、company 和 site_id 是唯一的。这意味着您不需要清理过程。而且只需要一行 SQL。 请参考this link of ***。它对我很有用。 我可以推荐这个解决方案(发布在另一个线程中):***.com/a/4685232/195835 也可以查看this answer 我不认为你的识别要删除的行的sn-p(使用HAVING)有效;它将删除所有重复的行,而我认为要求是保留一个。 【参考方案1】:

我有这个 SQLServer 的查询片段,但我认为它可以在其他 DBMS 中使用,只需稍作改动:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

我忘了告诉你,这个查询不会删除重复行中 ID 最低的行。如果这对您有用,请尝试以下查询:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

【讨论】:

如果一个组有两个以上的重复,那将不起作用。 很遗憾,mysql 不允许您从 ERROR 1093: You can't specify target table 'Table' for update in FROM clause 删除的表中进行选择 要解决"You can't specify target table 'Table' for update in FROM..." 错误,请使用:DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1),它会强制 MySQL 创建临时表。但是在大数据集里它很慢……在这种情况下,我会推荐 Andomar 的代码,它要快得多。【参考方案2】:

一个非常简单的方法是在 3 列上添加一个UNIQUE 索引。当您编写 ALTER 语句时,请包含 IGNORE 关键字。像这样:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

这将删除所有重复的行。作为一个额外的好处,未来的 INSERTs 是重复的将出错。与往常一样,您可能需要在运行此类操作之前进行备份...

【讨论】:

Interesting,但是 IGNORE 子句为删除这些重复项所做的假设可能与需求不符。将不正确的值截断为最接近的可接受匹配对您来说听起来不错? 仅作记录,如果您使用 InnoDB,那么您可能会遇到问题,有一个关于使用 ALTER IGNORE TABLE 和 InnoDB 数据库的已知错误。 The aforementioned bug @DarkMantis 提到和it's solution. 对于 InnoDB 表,首先执行以下查询:set session old_alter_table=1; 这在 5.7.4 中不再支持,dev.mysql.com/doc/refman/5.7/en/alter-table.html【参考方案3】:

MySQL 对引用您要从中删除的表有限制。您可以使用临时表解决此问题,例如:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

来自 Kostanos 在 cmets 中的建议: 对于数据库非常大的情况,上面唯一的慢查询是 DELETE。这个查询可能会更快:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

【讨论】:

@andomar,这很好用,除非 where 子句中的字段之一包含空值。示例:sqlfiddle.com/#!2/983f3/1 Insert SQL 是不是很贵?我想知道,因为它在我的 MySQL 数据库中超时。 这里唯一的慢查询是DELETE,以防你有大数据库。这个查询可能会更快:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id @Kostanos 不只是DELETE,还有INSERT 到临时表,花了我很长时间。所以 tmp 表的索引可以帮助很多,create index tmpTable_id_index on tmpTable (id),至少对我来说。 如果你的表很大,添加一个索引是值得的:-create temporary table tmpTable (id int, PRIMARY KEY (id));【参考方案4】:

如果IGNORE 语句在我的情况下不起作用,您可以使用以下语句:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;

【讨论】:

如果你有带有外键约束的 innoDB 设置,效果很好。 @magdmartin,但外部约束不会阻止表删除吗? IGNORE 语句对我不起作用,这对删除 500 万条记录非常有效。干杯。【参考方案5】:

我想更具体地说明我删除了哪些记录,所以这是我的解决方案:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)

【讨论】:

【参考方案6】:

您可以轻松地从此代码中删除重复记录..

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))

$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1)
    while($row = mysql_fetch_array($qry2))
        $city_arry[] = $row;

        

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++)


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            
    
    //exit;

【讨论】:

这是非常糟糕的表单 - 数据库任务应该在数据库中完成,它们要快得多,而不是在 php/mysql 之间不断发送数据,因为你比另一个更了解。跨度> 【参考方案7】:

我不得不对文本字段执行此操作,但遇到了索引上 100 个字节的限制。

我通过添加一列、对字段进行 md5 散列并进行更改来解决此问题。

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);

【讨论】:

【参考方案8】:

如果您不想更改列属性,则可以使用下面的查询。

由于您有一个具有唯一 ID 的列(例如,auto_increment 列),您可以使用它来删除重复项:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

在 MySQL 中,您可以使用NULL-safe equal operator(又名"spaceship operator")进一步简化它:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;

【讨论】:

这个解决方案不能正常工作,我试图做一些重复的记录,它做了类似的事情(20行受影响)但是如果你再次运行它会告诉你(4行受影响)等等直到你到达(0行受影响)这有点可疑,这对我来说最有效,它几乎相同,但它一次运行,我编辑了解决方案 @Nassim:你必须做一些与这个答案不同的事情,因为它非常适合我(在 MySQL 中)。 对于像我一样困惑的任何人,都需要使用 NULL 比较术语,因为 NULL 在 MySQL 中不等于 NULL。如果保证相关列不为 NULL,则可以省略这些项。 是的,接受的答案不再有效,因为 MYSQL 5.7 所以这应该是真正接受的答案,因为它是通用的,也不需要创建临时表。 非常慢,如果给定记录有很多副本(例如,100 减少到 1),并且许多记录具有这种条件。推荐***.com/a/4685232/199364。恕我直言,始终使用链接方法;它本质上是一种更快的技术。【参考方案9】:

此解决方案将将重复项移到一个表中,将唯一项移到另一个表中

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs

【讨论】:

你为什么加入工会而不只是SELECT * FROM jobs GROUP BY site_id, company, title, location【参考方案10】:

还有另一种解决方案:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...

【讨论】:

这与@rehriff 6 个月前提交的答案有何不同? @LawrenceDol 我想它更具可读性,而且我认为他的答案与我回答时不一样,我认为他的答案已被编辑。 嗯。记录数不多的情况下,我花了太长时间!【参考方案11】:

更快的方法是将不同的行插入到临时表中。使用删除,我花了几个小时从 800 万行的表中删除重复项。使用 insert 和 distinct,只用了 13 分钟。

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  

【讨论】:

你的第 4 行应该是 TRUNCATE TABLE tableName 和第 5 行应该是 INSERT INTO tableName SELECT * FROM tempTableName;【参考方案12】:

简单快速,适用于所有情况:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);

【讨论】:

错误代码:1055。SELECT 列表的表达式 #2 不在 GROUP BY 子句中,并且包含在功能上不依赖于 GROUP BY 子句中的列的非聚合列“dub.id”;这与 sql_mode=only_full_group_by 不兼容 您可以使用 sql_mode 禁用“硬控制”,请参阅 ***.com/questions/23921117/disable-only-full-group-by【参考方案13】:

每当我用谷歌搜索“从 mysql 中删除重复项”时,我都会一直访问这个页面,但是对于我的 theIGNORE 解决方案不起作用,因为我有一个 InnoDB mysql 表

这段代码在任何时候都能更好地工作

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = 您需要清理的表的名称

tableToclean_temp = 创建和删除的临时表

【讨论】:

【参考方案14】:

删除 MySQL 表上的重复项是一个常见问题,这通常是由于缺少约束以事先避免这些重复项的结果。但是这个常见的问题通常伴随着特定的需求......确实需要特定的方法。方法应该有所不同,具体取决于例如数据的大小、应该保留的重复条目(通常是第一个或最后一个)、是否有要保留的索引,或者我们是否要执行任何额外的操作对重复数据采取行动。

MySQL 本身也有一些特殊性,例如在执行表 UPDATE 时由于 FROM 原因无法引用同一个表(它会引发 MySQL 错误 #1093)。可以通过使用带有临时表的内部查询来克服此限制(如上面某些方法所建议的那样)。但这种内部查询在处理大数据源时表现不佳。

但是,确实存在一种更好的方法来删除重复项,它既高效又可靠,并且可以轻松适应不同的需求。

一般的想法是创建一个新的临时表,通常添加一个唯一约束以避免进一步重复,并将以前表中的数据插入到新表中,同时注意重复。这种方法依赖于简单的 MySQL INSERT 查询,创建一个新的约束以避免进一步的重复,并且跳过了使用内部查询来搜索重复项和应该保存在内存中的临时表的需要(因此也适合大数据源)。

这就是它的实现方式。假设我们有一个 employee 表,其中包含以下列:

employee (id, first_name, last_name, start_date, ssn)

为了删除具有重复ssn列的行,只保留找到的第一个条目,可以遵循以下过程:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

技术说明

第 1 行创建一个新的 tmp_eployee 表,其结构与 employee 表完全相同 第 2 行向新的 tmp_eployee 表添加 UNIQUE 约束以避免任何进一步的重复 第 3 行按 id 扫描原始 employee 表,将新员工条目插入新 tmp_eployee 表,同时忽略重复条目 第 4 行重命名表,以便新的 employee 表包含所有不重复的条目,并且以前数据的备份副本保存在 backup_employee

使用这种方法,160 万个寄存器在不到 200 秒的时间内转换为 6k 个。

Chetan,按照这个过程,您可以快速轻松地删除所有重复项并通过运行创建一个 UNIQUE 约束:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

当然,这个过程可以进一步修改,以适应删除重复项时的不同需求。下面是一些例子。

✔ 保留最后一个条目而不是第一个条目的变化

有时我们需要保留最后一个重复的条目而不是第一个。

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
在第 3 行,ORDER BY id DESC 子句使最后一个 ID 优先于其余 ID

✔ 对重复项执行某些任务的变体,例如对找到的重复项进行计数

有时我们需要对找到的重复条目进行一些进一步的处理(例如保持重复计数)。

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
在第 3 行,创建了一个新列 n_duplicates 在第 4 行,INSERT INTO ... ON DUPLICATE KEY UPDATE 查询用于在发现重复项时执行附加更新(在本例中,增加计数器) INSERT INTO ... ON DUPLICATE KEY UPDATE 查询可用于对找到的重复项执行不同类型的更新。

✔ 重新生成自动增量字段 id 的变化

有时我们使用自增字段,为了使索引尽可能紧凑,我们可以利用删除重复项在新临时表中重新生成自增字段。

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
在第 3 行,不是选择表中的所有字段,而是跳过 id 字段,以便数据库引擎自动生成一个新字段

✔ 更多变化

根据所需的行为,还可以进行许多进一步的修改。例如,以下查询将使用第二个临时表,除了 1) 保留最后一个条目而不是第一个条目; 2) 增加对找到的重复项的计数器;也 3) 重新生成自动增量字段 id,同时保持输入顺序与以前的数据相同。

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;

【讨论】:

这个问题是你需要空间来复制你的数据。【参考方案15】:

一种易于理解且无需主键的解决方案:

    添加一个新的布尔列

    alter table mytable add tokeep boolean;
    

    在重复列和新列上添加约束

    alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);
    

    将布尔列设置为真。由于新的约束,这只会在重复的行之一上成功

    update ignore mytable set tokeep = true;
    

    删除未标记为tokeep的行

    delete from mytable where tokeep is null;
    

    删除添加的列

    alter table mytable drop tokeep;
    

我建议您保留您添加的约束,以便将来防止新的重复。

【讨论】:

这在 mysql 5.7 中运行得非常好,接受的解决方案不再起作用 这太棒了,非常感谢【参考方案16】:

使用 DELETE JOIN 语句删除重复行 MySQL 为您提供了 DELETE JOIN 语句,您可以使用它来快速删除重复的行。

以下语句删除重复行并保留最高id:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

【讨论】:

【参考方案17】:

如果您有一个包含大量记录的大表,那么上述解决方案将不起作用或花费太多时间。那么我们有不同的解决方案

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;

【讨论】:

【参考方案18】:

我找到了一个简单的方法。 (保持最新)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;

【讨论】:

为什么这在 mysql 上不起作用?它在t1 附近给出了意外的令牌 我用过很多次,都有效。给我看看你的实际脚本【参考方案19】:

从 8.0 (2018) 版本开始,MySQL 终于支持window functions

窗口函数既方便又高效。这是一个演示如何使用它们来解决此作业的解决方案。

在子查询中,我们可以使用ROW_NUMBER()column1/column2 组内的表中的每条记录分配一个位置,按id 排序。如果没有重复,记录将获得行号1。如果存在重复,它们将按升序排列id(从1 开始)。

一旦记录在子查询中正确编号,外部查询只会删除行号不为 1 的所有记录。

查询:

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)

【讨论】:

有趣。或者,为了提高性能,我们可以使用子查询创建一个临时表,但过滤rn = 1。然后我们删除原来的并重命名。【参考方案20】:

为了复制具有唯一列的记录,例如COL1,COL2,COL3 不应该被复制(假设我们错过了表结构中唯一的 3 列,并且在表中创建了多个重复条目)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

希望对开发者有所帮助。

【讨论】:

【参考方案21】:

删除表中的重复记录。

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);

【讨论】:

【参考方案22】:

这是我使用的,它有效:

create table temp_table like my_table;

t_id 是我唯一的专栏

insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;

【讨论】:

【参考方案23】:

这将删除标题、公司和网站具有相同值的重复行。将保留第一次出现,其余所有重复项将被删除

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;

【讨论】:

【参考方案24】:

我有一个表忘记在 id 行中添加主键。虽然在 id 上有 auto_increment。但是有一天,一个东西在数据库上重放了 mysql bin 日志,其中插入了一些重复的行。

我删除了重复的行

    选择唯一的重复行并导出它们

    select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c &gt; 1 group by T1.id;

    按 id 删除重复行

    从导出的数据中插入行。

    然后在id上添加主键

【讨论】:

【参考方案25】:

使用DELETE JOIN 语句删除重复行:

DELETE t1 FROM table_name t1
JOIN table_name t2
WHERE
    t1.id < t2.id AND
    t1.title = t2.title AND t1.company = t2.company AND t1.site_id = t2.site_id;

【讨论】:

为什么是t1.id &lt; t2.id 而不是t1.id &lt;&gt; t2.id?如果 t1 和 t2 互换,这将防止人为错误。 已经有一些DELETE...JOIN 语法的答案,包括自然连接和内部连接。这似乎没有添加任何新内容。【参考方案26】:

如果您尝试删除其中一个重复项并保留另一个,这是完美的。请注意,如果没有子查询,您将收到 #1093 错误。

DELETE FROM table_name WHERE id IN (SELECT * FROM (SELECT n.id FROM table_name n WHERE n.column2 != "value" GROUP BY n.column HAVING COUNT(n.column ) > 1) x)

【讨论】:

以上是关于删除 MySQL 中的重复行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:删除行中的重复条目不起作用

mysql删除完全重复行,求教

mysql怎么去除重复数据

删除大型 postgresql 数据库表中的重复行

从 mySQL 数据库中删除列重复的重复行

pandas删除数据行中的重复数据行基于dataframe所有列删除重复行基于特定数据列或者列的作何删除重复行删除重复行并保留重复行中的最后一行pandas删除所有重复行(不进行数据保留)