如何删除没有临时表的 MySQL 表中的所有重复记录

Posted

技术标签:

【中文标题】如何删除没有临时表的 MySQL 表中的所有重复记录【英文标题】:How do I delete all the duplicate records in a MySQL table without temp tables 【发布时间】:2012-12-12 08:26:58 【问题描述】:

我已经看到了这方面的许多变体,但没有一个完全符合我想要完成的目标。

我有一个表格,TableA,其中包含用户对可配置问卷的回答。列是member_id, quiz_num, question_num, answer_num

不知何故,一些成员的答案被提交了两次。所以我需要删除重复的记录,但要确保留下一行。

没有主要列,因此可能有两三行包含完全相同的数据。

是否有删除所有重复项的查询?

【问题讨论】:

您是否有理由反对创建可以在删除重复项后使用简单的 drop table 语句删除的临时表?我可以为您提供 SQL 来创建一个只有唯一记录的临时表,从原始表中删除记录,加载唯一数据然后删除临时表。如果它不是一个庞大的数据库,这应该不会花费太长时间。这里有一篇关于这个过程的好文章:databasejournal.com/features/mysql/article.php/10897_2201621_2/… How to delete duplicate records in mysql database?的可能重复 我正在寻找一种可以轻松(从广义上讲)即时重复的解决方案。使用额外的表,无论是否临时,都意味着在检测到此情况时随时关闭站点。最好的解决方案是首先确保它永远不会发生,但在此之前,我希望定期进行此检查/修复,以确保报告不会给出不稳定的结果 正如我在回答中提到的,在您的表上创建一个索引它将删除重复数据,并且以后也不允许您添加重复数据 Remove duplicate rows in MySQL的可能重复 【参考方案1】:

这不使用 TEMP 表,而是使用真实表。如果问题只是临时表而不是表创建或删除表,这将起作用:

SELECT DISTINCT * INTO TableA_Verify FROM TableA;

DROP TABLE TableA;

RENAME TABLE TableA_Verify TO TableA;

【讨论】:

【参考方案2】:

在您的表上添加唯一索引

ALTER IGNORE TABLE `TableA`   
ADD UNIQUE INDEX (`member_id`, `quiz_num`, `question_num`, `answer_num`);

另一种方法是:

在表中添加主键,然后您可以使用以下查询轻松地从表中删除重复项:

DELETE FROM member  
WHERE id IN (SELECT * 
             FROM (SELECT id FROM member 
                   GROUP BY member_id, quiz_num, question_num, answer_num HAVING (COUNT(*) > 1)
                  ) AS A
            );

【讨论】:

我会继续选择这个作为答案。最后我将不得不使用临时表来打扫房间,但我会确保添加 UNIQUE INDEX,这样以后就不会出现这个问题了。现在我只需要弄清楚事情是如何被复制的。 注意:如果您的表包含 3 个或更多相同行的重复项,则需要多次运行此操作 如果能解释使用 IGNORE 添加唯一索引的后果,这个答案会更有帮助:显然它会删除重复的行?我们知道它是否保留第一个吗? 看起来alter ignore table 可能很快就会消失:dev.mysql.com/worklog/task/?id=7395 @juacala 是正确的:“从 MySQL 5.7.4 开始,ALTER TABLE 的 IGNORE 子句被删除,它的使用会产生错误。”【参考方案3】:

您可以删除所有寄存器 (delete from TableA;),而不是 drop table TableA,然后使用来自 TableA_Verify (insert into TAbleA select * from TAbleA_Verify) 的寄存器填充原始表。这样您就不会丢失对原始表的所有引用(索引,...)

CREATE TABLE TableA_Verify AS SELECT DISTINCT * FROM TableA;

DELETE FROM TableA;

INSERT INTO TableA SELECT * FROM TAbleA_Verify;

DROP TABLE TableA_Verify;

【讨论】:

【参考方案4】:

感谢 jveirasv 上面的回答。

如果您需要删除特定列集的重复项,您可以使用它(例如,如果您的表中有不同的时间戳

CREATE TABLE TableA_Verify AS SELECT * FROM TableA WHERE 1 GROUP BY [COLUMN TO remove duplicates BY];

DELETE FROM TableA;

INSERT INTO TableA SELECT * FROM TAbleA_Verify;

DROP TABLE TableA_Verify;

【讨论】:

【参考方案5】:

在您的表上添加唯一索引:

ALTER IGNORE TABLE TableA   
ADD UNIQUE INDEX (member_id, quiz_num, question_num, answer_num);

效果很好

【讨论】:

谢谢,它可以工作,但我收到 1 个警告:1681 'IGNORE' 已弃用,将在未来的版本中删除。重复:1 警告:1【参考方案6】:

如果您不使用任何主键,则一次执行以下查询。通过替换值:

# table_name - Your Table Name
# column_name_of_duplicates - Name of column where duplicate entries are found

create table table_name_temp like table_name;
insert into table_name_temp select distinct(column_name_of_duplicates),value,type from table_name group by column_name_of_duplicates;
delete from table_name;
insert into table_name select * from table_name_temp;
drop table table_name_temp
    创建临时表并存储不同(非重复)值 空原表 将值从临时表插入到原始表中 删除临时表

始终建议在使用数据库之前对其进行备份。

【讨论】:

【参考方案7】:

如 cmets 中所述,如果项目多次重复,则必须多次运行 Saharsh Shah 答案中的查询。

这是一个不删除任何数据,并将数据始终保留在原始表中的解决方案,允许在保持表“活动”的同时删除重复项:

alter table tableA add column duplicate tinyint(1) not null default '0';

update tableA set
duplicate=if(@member_id=member_id
             and @quiz_num=quiz_num
             and @question_num=question_num
             and @answer_num=answer_num,1,0),
member_id=(@member_id:=member_id),
quiz_num=(@quiz_num:=quiz_num),
question_num=(@question_num:=question_num),
answer_num=(@answer_num:=answer_num)
order by member_id, quiz_num, question_num, answer_num;

delete from tableA where duplicate=1;

alter table tableA drop column duplicate;

这基本上检查当前行是否与最后一行相同,如果是,则将其标记为重复(顺序语句确保重复显示将彼此相邻)。然后删除重复的记录。我删除了末尾的 duplicate 列,使其恢复到原来的状态。

看起来alter table ignore 也可能很快就会消失:http://dev.mysql.com/worklog/task/?id=7395

【讨论】:

【参考方案8】:

另一种方法是创建一个具有相同结构的新临时表。

CREATE TABLE temp_table AS SELECT * FROM original_table LIMIT 0

然后在表中创建主键。

ALTER TABLE temp_table ADD PRIMARY KEY (primary-key-field)

最后从原表中复制所有记录,忽略重复记录。

INSERT IGNORE INTO temp_table AS SELECT * FROM original_table

现在您可以删除原始表并重命名新表。

DROP TABLE original_table
RENAME TABLE temp_table TO original_table

【讨论】:

【参考方案9】:

在mysql 5中测试。不知道其他版本。 如果要保留 id 值最低的行:

DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id > n2.id AND n1.member_id = n2.member_id and n1.answer_num =n2.answer_num

如果要保留id值最高的行:

DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id < n2.id AND n1.member_id = n2.member_id and n1.answer_num =n2.answer_num

【讨论】:

以上是关于如何删除没有临时表的 MySQL 表中的所有重复记录的主要内容,如果未能解决你的问题,请参考以下文章

Mysql数据库中多条重复数据,如何只删除一条?

sql如何创建临时表

如何用SQL语句删除两个表中相同的记录?

查询删除临时表中的重复行

记一次MySQL Group by 的坑

mysql删除表的三种方式