如何删除 MySQL 表中的副本?

我需要在 MySQL表上为指定的 sid 复制 DELETE行。

如何使用 SQL 查询执行此操作?

DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"

就像这样,但我不知道怎么做。

241588 次浏览

接下来删除所有 SID-s 的副本,而不仅仅是一个。

还有临时工桌

CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;


DROP TABLE table;
RENAME TABLE table_temp TO table;

因为 temp_table是新创建的,所以它没有索引。在删除副本之后,您需要重新创建它们。您可以使用 SHOW INDEXES IN table检查表中的索引

没有临时工表:

DELETE FROM `table` WHERE id IN (
SELECT all_duplicates.id FROM (
SELECT id FROM `table` WHERE (`title`, `SID`) IN (
SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
)
) AS all_duplicates
LEFT JOIN (
SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
) AS grouped_duplicates
ON all_duplicates.id = grouped_duplicates.id
WHERE grouped_duplicates.id IS NULL
)

这样就可以在适当的位置删除重复项,而无需创建新表。

ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)

注意: 这只有在 index 适合内存时才能正常工作。

此过程将删除表中的所有重复项(包括多个) ,保留最后一个重复项。这是 检索每组中的最后记录的扩展

希望这对某人有用。

DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));


INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);


DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);

假设您有一个 employee表,其中包含以下列:

employee (first_name, last_name, start_date)

为了删除具有重复 first_name列的行:

delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name

就地删除 MySQL 中的重复行(假设您有一个时间戳 coll 进行排序)演练:

创建表并插入一些行:

create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
+------+----------+---------------------+
| foo  | bar      | baz                 |
+------+----------+---------------------+
|    1 | skipper  | 2014-08-25 14:21:54 |
|    1 | skipper  | 2014-08-25 14:21:59 |
|    3 | kowalski | 2014-08-25 14:22:09 |
|    3 | kowalski | 2014-08-25 14:22:13 |
|    3 | kowalski | 2014-08-25 14:22:15 |
|    4 | rico     | 2014-08-25 14:22:22 |
+------+----------+---------------------+
6 rows in set (0.00 sec)

删除原有的副本:

delete a
from penguins a
left join(
select max(baz) maxtimestamp, foo, bar
from penguins
group by foo, bar) b
on a.baz = maxtimestamp and
a.foo = b.foo and
a.bar = b.bar
where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo  | bar      | baz                 |
+------+----------+---------------------+
|    1 | skipper  | 2014-08-25 14:21:59 |
|    3 | kowalski | 2014-08-25 14:22:15 |
|    4 | rico     | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)

完成后,删除重复的行,保留按时间戳显示的最后一行。

对于那些没有时间戳或唯一列的人。

你没有一个 timestamp或一个唯一的索引列排序?你生活在一种堕落的状态中。您必须执行其他步骤来删除重复的行。

创建企鹅表并添加一些行

create table penguins(foo int, bar varchar(15));
insert into penguins values(1, 'skipper');
insert into penguins values(1, 'skipper');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(3, 'kowalski');
insert into penguins values(4, 'rico');
select * from penguins;
# +------+----------+
# | foo  | bar      |
# +------+----------+
# |    1 | skipper  |
# |    1 | skipper  |
# |    3 | kowalski |
# |    3 | kowalski |
# |    3 | kowalski |
# |    4 | rico     |
# +------+----------+

复制第一个表并复制到其中

drop table if exists penguins_copy;
create table penguins_copy as ( SELECT foo, bar FROM penguins );


#add an autoincrementing primary key:
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first;


select * from penguins_copy;
# +-----+------+----------+
# | moo | foo  | bar      |
# +-----+------+----------+
# |   1 |    1 | skipper  |
# |   2 |    1 | skipper  |
# |   3 |    3 | kowalski |
# |   4 |    3 | kowalski |
# |   5 |    3 | kowalski |
# |   6 |    4 | rico     |
# +-----+------+----------+

最大汇总对新的 moo 指数起作用:

delete a from penguins_copy a left join(
select max(moo) myindex, foo, bar
from penguins_copy
group by foo, bar) b
on a.moo = b.myindex and
a.foo = b.foo and
a.bar = b.bar
where b.myindex IS NULL;


#drop the extra column on the copied table
alter table penguins_copy drop moo;
select * from penguins_copy;


#drop the first table and put the copy table back:
drop table penguins;
create table penguins select * from penguins_copy;

观察及清理

drop table penguins_copy;
select * from penguins;
+------+----------+
| foo  | bar      |
+------+----------+
|    1 | skipper  |
|    3 | kowalski |
|    4 | rico     |
+------+----------+
Elapsed: 1458.359 milliseconds

那个大 SQL 删除语句在做什么?

别名为“ a”的餐桌企鹅与别名为“ b”的餐桌企鹅子集合在一起。右手边的表‘ b’是一个子集,它找到了按 foo 和 bar 列分组的最大时间戳[或 max moo ]。这与左边的表‘ a’匹配。(foo,bar,baz)左边的是表中的每一行。右边的子集‘ b’有一个(maxtime戳,foo,bar) ,它只与最大值的那个子集的左边匹配。

每个不是 max 的行的值 maxtimestamp 都为 NULL。向下筛选这些 NULL 行,就会得到一组按 foo 和 bar 分组的所有行,这些行不是最新的时间戳 baz。删掉这些。

运行此命令之前,请对表进行备份。

防止这个问题再次发生在这张桌子上:

如果你把这个弄好了,它就能扑灭你的“复排”火焰。很好。现在,在表上(在这两列上)定义一个新的复合惟一键,以防止首先添加更多重复项。

就像一个好的免疫系统一样,在执行插入操作时,不好的行甚至不应该被允许进入表。后来所有这些节目添加副本将广播他们的抗议,当你修复他们,这个问题再也不会出现。

delete from `table` where `table`.`SID` in
(
select t.SID from table t join table t1 on t.title = t1.title  where t.SID > t1.SID
)

如果您计算它们,然后向删除查询添加一个限制,只留下一个限制,那么这种方法是否可行?

例如,如果您有两个或多个查询,请像下面这样编写查询:

DELETE FROM table WHERE SID = 1 LIMIT 1;

爱@eric 的回答,但它似乎不工作,如果你有一个真正的大表(我得到 The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay时,我试图运行它)。因此,我将连接查询限制为只考虑重复的行,最后得到:

DELETE a FROM penguins a
LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
FROM penguins
GROUP BY deviceId HAVING num > 1) b
ON a.baz != b.keepBaz
AND a.foo = b.foo
WHERE b.foo IS NOT NULL

在这种情况下,WHERE 子句允许 MySQL 忽略任何没有重复的行,如果这是重复的第一个实例,也会忽略,因此只有后续的重复才会被忽略。将 MIN(baz)更改为 MAX(baz)以保留最后一个实例而不是第一个实例。

答案很简单:

delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated
from target_table GROUP BY field_being_repeated) b
on a.field_being_repeated = b.field_being_repeated
and a.id_field = b.id_field
where b.id_field is null;

这对我似乎总是奏效:

CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;

每个受骗者和其他非受骗者的身份都是最低的。

我还采取了以下措施,这样在删除之后,欺骗问题就不再发生了:

CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;

换句话说,我创建一个第一个表的副本,在我不想重复的字段上添加一个唯一的索引,然后执行一个 Insert IGNORE,它的优点是不会像一个正常的 Insert那样,在第一次尝试基于这两个字段添加一个重复的记录时失败,而是忽略任何这样的记录。

移动 fwd 将不可能根据这两个字段创建任何重复记录。

您可以只使用 DISTINCT 子句来选择“已清理”列表(给你就是一个非常简单的示例)。

这项工作对我来说,删除旧的记录:

delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);

您可以将 min (e.id)替换为 max (e.id)以删除最新的记录。

delete p from
product p
inner join (
select max(id) as id, url from product
group by url
having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;

这适用于大型表格:

 CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;


DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;

删除最旧的更改 max(id)min(id)

自己在一个巨大的数据库中遇到这个问题之后,我对其他答案的性能并没有完全印象深刻。我希望只保留最新的重复行,并删除其余的行。

在没有临时表的一个查询语句中,这种方法对我来说效果最好,

DELETE e.*
FROM employee e
WHERE id IN
(SELECT id
FROM (SELECT MIN(id) as id
FROM employee e2
GROUP BY first_name, last_name
HAVING COUNT(*) > 1) x);

唯一需要注意的是,我必须多次运行查询,但即使如此,我发现它比其他选项更适合我。

这将使列 column_name成为主键,同时忽略所有错误。因此,它将删除具有 column_name重复值的行。

ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);

当从表中删除重复数据时,只有几个基本步骤:

  • 退后!
  • 找到重复的行
  • 删除重复的行

以下是完整的教程: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473

另一个简单的方法... 使用更新忽略:

必须对一个或多个列使用索引(类型索引)。 创建一个新的临时引用列(不是索引的一部分)。在本专栏文章中,通过使用忽略子句对其进行更新来标记唯一性。一步一步来:

添加一个临时引用列来标记唯一性:

ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;

这将向表中添加一列。

更新表,尝试将所有内容标记为惟一的,但是忽略由于重复键问题而可能出现的错误(将跳过记录) :

UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;

= > 你会发现你的重复记录不会被标记为惟一 = ‘ Yes’,换句话说,每组重复记录中只有一条会被标记为唯一。

删除所有不是唯一的东西:

DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';

这将删除所有重复的记录。

放下纵队。

ALTER TABLE `yourtable` DROP `unique`;

删除 MySQL 表上的重复数据是一个常见问题,这通常伴随着特定的需求。如果有人感兴趣的话,这里(删除 MySQL 中的重复行)我将解释如何使用一个临时表以一种可靠和快速的方式删除 MySQL 副本,这种方式也适用于处理大数据源(以及不同用例的示例)。

Ali ,在你的情况下,你可以运行这样的程序:

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;


-- add a unique constraint
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);


-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;


-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;

以下内容适用于所有表

CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;

我发现 Werner 的解决方案 以上是最方便的,因为它不管主键是否存在都能正常工作,不会干扰表,使用防止将来出现问题的普通 sql,这是非常容易理解的。

正如我在评论中所说,这个解决方案还没有得到正确的解释。 根据这个,这是我的。

1)添加一个新的布尔列

alter table mytable add tokeep boolean;

2)在重复的列和新列上添加一个约束

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

3)将布尔列设置为 true。由于新的约束,这将仅在重复的一行上成功

update ignore mytable set tokeep = true;

4)删除未标记为 tokeep 的行

delete from mytable where tokeep is null;

5)删除添加的列

alter table mytable drop tokeep;

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

我认为这将工作基本上复制表和清空它,然后只把不同的值放回到它,但请仔细检查之前,对大量的数据这样做。

创建表的复本

像 oldtablename 一样创建 table temp _ table; 插入 temp _ table select * from oldtablename;

清空原来的桌子

从旧表名中删除 * ;

将所有不同的值从复制的表复制回原始表

INSERT oldtablename SELECT * from temp _ table group by firstname,lastname,dob

删除临时表。

删除表 temp _ Table

您需要按要保持不同的所有字段进行分组。

DELETE T2
FROM   table_name T1
JOIN   same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)

我通常是这样消除副本的

  1. 添加一个临时列,命名为任何你想要的(我将称为活动)
  2. 通过您认为不应该重复的字段进行分组,并将其活动设置为1,分组通过将只选择该列的一个重复值(不会选择重复值)
  3. 删除那些活动为零的
  4. 降落柱激活
  5. 可以选择(如果符合您的目的) ,为这些列添加唯一索引,以避免再次出现重复

如果希望保留 id 值最低的行:

 DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id > n2.id AND n1.email = n2.email

如果希望保留 id 值最高的行:

 DELETE n1 FROM 'yourTableName' n1, 'yourTableName' n2 WHERE n1.id < n2.id AND n1.email = n2.email