我需要DELETE
为指定的sid复制行MySQL
表。
如何使用SQL查询做到这一点?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
这样的东西,但我不知道该怎么做。
我需要DELETE
为指定的sid复制行MySQL
表。
如何使用SQL查询做到这一点?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
这样的东西,但我不知道该怎么做。
Answers:
这将删除重复项,而无需创建新表
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
注意:仅当索引适合内存时才有效
ALTER IGNORE
。
ALTER TABLE foo ENGINE MyISAM
解决它,之后又换了引擎。
假设您有一个表格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
employee
针对一个索引匹配和>
对一个索引的检查而对自身联接。SELECT MAX(ID) FROM t GROUP BY unique
然后再JOIN
匹配ID
到完全匹配会更好MAX(ID)
吗?
接下来,删除所有SID的重复项,而不仅仅是单个。
带临时表
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
)
SELECT * FROM table GROUP BY title, SID;
这完全取决于您对自己在做什么的了解。
创建表并插入一些行:
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 delete语句在做什么?
别名为“ a”的表企鹅在称为别名“ b”的表企鹅的子集上保持连接。右表“ b”是一个子集,可找到由列foo和bar分组的最大时间戳[或max moo]。这与左表“ a”匹配。左侧的(foo,bar,baz)表格中的每一行。右侧子集“ b”具有(maxtimestamp,foo,bar),仅在最大的那一个上与左侧匹配。
非最大的每一行的maxtimestamp值为NULL。筛选掉这些NULL行,您将获得一组由foo和bar分组的所有行,这些行不是最新的时间戳baz。删除那些。
运行此表之前,请对其进行备份。
防止此问题在此表上再次发生:
如果您能做到这一点,那么它就会扑灭您的“重复行”。大。现在,在表上(这两列上)定义一个新的复合唯一键,以防止首先添加更多重复项。
就像一个好的免疫系统一样,插入时也不应该将坏行插入表中。后来,所有添加重复项的程序都会广播他们的抗议,而当您修复它们时,此问题就再也不会出现。
ID
列,则该ON
子句只需要与该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);
唯一的警告是,我必须多次运行查询,但是即使如此,我发现它对我来说比其他选项更好。
这似乎总是为我工作:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
这样,每个重复项和其余非重复记录中的ID最低。
我还采取了以下措施,以使删除后不再出现重复问题:
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
换句话说,我创建了第一个表的副本,在我不希望重复的字段上添加了唯一索引,然后执行了一个Insert IGNORE
具有不会像平常一样失败的优点Insert
第一次尝试添加基于两个字段的重复记录,而忽略任何此类记录。
向前移动,就不可能基于这两个字段创建任何重复的记录。
ORDER BY
,SELECT
以确保实际将哪个记录转交给NoDupeTable
?
ORDER by ID Asc
可以,所以我还是要编辑我的答案。
Select Max(ID)
,然后做,Order by Max(ID)
但所有要做的就是颠倒插入的顺序。要获取最高的ID,我相信需要更复杂的选择联接,无论您如何在上方订购,都将从较低的ID获取字段值。
MAX(ID)
或者MIN(ID)
和列名,而不是*
在SELECT FROM DupeTable
虽然,否则你会刚刚得到的一个ID
的随机。实际上,许多SQL甚至MySQL严格要求在GROUP BY
子句中未指定的每一列上调用聚合函数。
ID,First,Last,Notes
和记录的记录1,Bob,Smith,NULL
,2,Bob,Smith,Arrears
然后执行a SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Last
都将返回相同的记录1,但ID不同。Max(ID)将返回,2,Bob,Smith,NULL
而Min(ID)将返回1,Bob,Smith,NULL
。我相信要获得笔记中带有“欠款”的第二张唱片,需要参加。
这是一个简单的答案:
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;
and a.id_field = b.id
LEFT JOIN
以b
只需要比较b.id
= a.id_field
假设field_id
是一个独特的自动递增ID。所以a.field_being_repeated = b.field_being_repeated
是无关紧要的。(也b.id_field
不会在此查询它的存在b.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;
我在上面找到了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)删除未标记为保留的行
delete from mytable where tokeep is null;
5)删除添加的列
alter table mytable drop tokeep;
我建议您保留添加的约束,以便将来避免新的重复项。
此过程将删除表中的所有重复项(包括多个),并保留最后一个重复项。这是检索每个组中的最后一条记录的扩展
希望这对某人有用。
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);
另一种简单的方法...使用UPDATE IGNORE:
U必须在一个或多个列上使用索引(类型索引)。创建一个新的临时参考列(不属于索引)。在此列中,您可以通过用ignore子句更新唯一性来标记唯一性。一步步:
添加一个临时参考列以标记唯一性:
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
=>这会将一列添加到您的表中。
更新表,尝试将所有内容标记为唯一,但忽略由于重复的密钥问题而导致的可能的错误(将跳过记录):
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
=>您会发现重复记录不会被标记为唯一='是',换句话说,每组重复记录中只有一个会被标记为唯一。
删除所有不唯一的内容:
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
=>这将删除所有重复的记录。
放下列...
ALTER TABLE `yourtable` DROP `unique`;
unique
必须将列与当前正在复制的列一起添加到唯一约束中,否则整个事情将不起作用,因为SET unique
='Yes'将永远不会失败。
unique
是一个mysql关键字。因此,它必须具有反引号(如已正确显示)。在该列中使用另一个单词可能会更方便。
删除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;
喜欢@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)
保留最后一个实例而不是第一个实例。
这适用于大表:
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)
这将使该列成column_name
为主键,同时忽略所有错误。因此它将删除具有重复值的行column_name
。
ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);
DELETE T2
FROM table_name T1
JOIN same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)
从表中删除重复数据时,只有几个基本步骤:
这是完整的教程:https : //blog.teamsql.io/deleting-duplicate-data-3541485b3473