Ali*_*der 154 mysql duplicates
我需要DELETE
在MySQL
表上为指定的sid复制行.
如何使用SQL查询执行此操作?
DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"
Run Code Online (Sandbox Code Playgroud)
像这样的东西,但我不知道该怎么做.
use*_*291 210
这样可以在不创建新表的情况下删除重复项
ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)
Run Code Online (Sandbox Code Playgroud)
注意:只有在索引适合内存时才能正常工作
Abh*_*y_D 121
假设您有一个表employee
,其中包含以下列:
employee (first_name, last_name, start_date)
Run Code Online (Sandbox Code Playgroud)
要删除具有重复first_name
列的行:
delete
from employee using employee,
employee e1
where employee.id > e1.id
and employee.first_name = e1.first_name
Run Code Online (Sandbox Code Playgroud)
Kam*_*zot 56
删除所有SID-s的重复项后,不仅是单个SID-s.
有临时表
CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;
DROP TABLE table;
RENAME TABLE table_temp TO table;
Run Code Online (Sandbox Code Playgroud)
由于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
)
Run Code Online (Sandbox Code Playgroud)
Eri*_*ski 49
创建表并插入一些行:
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)
Run Code Online (Sandbox Code Playgroud)
然后删除重复项:
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)
Run Code Online (Sandbox Code Playgroud)
结果:
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 |
# +------+----------+
Run Code Online (Sandbox Code Playgroud)
删除语句是做什么的
伪代码:按要删除重复项的两列对行进行分组.使用最大聚合选择要保留的每个组的一行.左连接返回左表中的所有行,右表中的匹配行.在这种情况下,左表包含表中的所有行,右表只包含那些为NULL的行(不是每个组要保留的一行).删除这些行,每组只剩下一个唯一的行.
更多技术说明,你应该如何阅读sql delete语句:
具有别名'a'的表企鹅将被连接在称为别名'b'的表企鹅的子集上.作为子集的右手表'b'找到按foo和bar分组的最大时间戳.这与左手表'a'相匹配.左边的(foo,bar,baz)表格中的每一行都有.右手子集'b'具有(maxtimestamp,foo,bar),其仅与最大的那个匹配.
不是max的每一行都有maxtimestamp值为NULL.过滤掉那些NULL行,你有一组按foo和bar分组的所有行,这些行不是最新的时间戳baz.删除那些.
在运行此表之前备份表.
防止在此表上再次发生此问题:
如果你有这个工作,它会发出你的"重复行"火.大.你的工作尚未完成.在表上(在这两列上)定义新的复合唯一键,以防止在第一个位置添加更多重复项.就像一个好的免疫系统一样,在插入时甚至不允许将坏行放入桌面.稍后所有这些程序添加重复项将播放他们的抗议,当你修复它们时,这个问题再也不会出现了.
use*_*739 13
这似乎总是对我有用:
CREATE TABLE NoDupeTable LIKE DupeTable;
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;
Run Code Online (Sandbox Code Playgroud)
这保留了每个欺骗和其他非欺骗记录的最低ID.
我还采取了以下措施,以便在删除后不再发生欺骗问题:
CREATE TABLE NoDupeTable LIKE DupeTable;
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;
Run Code Online (Sandbox Code Playgroud)
换句话说,我创建了第一个表的副本,在我不想要重复的字段上添加一个唯一索引,然后执行一个Insert IGNORE
优点是不会像Insert
第一次尝试添加时那样正常失败基于这两个字段的重复记录,而忽略任何此类记录.
移动fwd,根据这两个字段创建任何重复记录变得不可能.
sea*_*ers 13
在我自己遇到这个问题之后,在一个庞大的数据库中,我对其他任何答案的表现都没有给我留下深刻的印象.我想只保留最新的重复行,并删除其余的行.
在一个查询语句中,没有临时表,这对我来说效果最好,
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);
Run Code Online (Sandbox Code Playgroud)
唯一需要注意的是,我必须多次运行查询,但即便如此,我发现它比其他选项更适合我.
小智 7
这是一个简单的答案:
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;
Run Code Online (Sandbox Code Playgroud)
小智 7
以下适用于所有表
CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;
Run Code Online (Sandbox Code Playgroud)
我发现上面的Werner 解决方案是最方便的,因为无论是否存在主键,它都可以工作,不会弄乱表,使用面向未来的普通 sql,非常容易理解。
正如我在评论中所述,该解决方案尚未得到正确解释。所以这是我的,基于它。
1) 添加一个新的布尔列
alter table mytable add tokeep boolean;
Run Code Online (Sandbox Code Playgroud)
2)在重复列和新列上添加约束
alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);
Run Code Online (Sandbox Code Playgroud)
3) 将布尔列设置为 true。由于新的约束,这只会在重复的行之一上成功
update ignore mytable set tokeep = true;
Run Code Online (Sandbox Code Playgroud)
4) 删除没有被标记为 tokeep 的行
delete from mytable where tokeep is null;
Run Code Online (Sandbox Code Playgroud)
5)删除添加的列
alter table mytable drop tokeep;
Run Code Online (Sandbox Code Playgroud)
我建议您保留您添加的约束,以便将来防止出现新的重复项。
这项工作让我删除旧记录:
delete from table where id in
(select min(e.id)
from (select * from table) e
group by column1, column2
having count(*) > 1
);
Run Code Online (Sandbox Code Playgroud)
您可以将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;
Run Code Online (Sandbox Code Playgroud)
另一种简单的方法......使用UPDATE IGNORE:
你必须在一列或多列上使用索引(类型索引)。创建一个新的临时引用列(不是索引的一部分)。在此列中,您通过使用 ignore 子句更新来标记唯一项。一步步:
添加一个临时引用列来标记唯一性:
ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;
Run Code Online (Sandbox Code Playgroud)
=> 这将在您的表格中添加一列。
更新表,尝试将所有内容标记为唯一,但忽略由于重复键问题可能导致的错误(记录将被跳过):
UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;
Run Code Online (Sandbox Code Playgroud)
=> 你会发现你的重复记录不会被标记为唯一 = '是',换句话说,每组重复记录中只有一个被标记为唯一。
删除所有不唯一的内容:
DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';
Run Code Online (Sandbox Code Playgroud)
=> 这将删除所有重复记录。
删除列...
ALTER TABLE `yourtable` DROP `unique`;
Run Code Online (Sandbox Code Playgroud)