删除除一个以外的所有重复项

时间:2012-09-18 18:36:20

标签: mysql sql

我们有business_usersuser_id的表business_id,我们有重复项。 如何编写将删除除一个重复项以外的所有重复项的查询?

2 个答案:

答案 0 :(得分:9)

完全相同的行

如果你想避免完全相同的行,我首先理解你的问题,那么你可以选择唯一的行到一个单独的表并从中重新创建表数据。

CREATE TEMPORARY TABLE tmp SELECT DISTINCT * FROM business_users;
DELETE FROM business_users;
INSERT INTO business_users SELECT * FROM tmp;
DROP TABLE tmp;

如果有任何引用此表的外键约束,请注意,因为临时删除行可能会导致其他位置的级联删除。

引入唯一约束

如果您只关心user_idbusiness_id对,您可能希望将来避免引入重复项。您可以将现有数据移动到临时表,添加约束,然后将表数据移回,忽略重复项。

CREATE TEMPORARY TABLE tmp SELECT * FROM business_users;
DELETE FROM business_users;
ALTER TABLE business_users ADD UNIQUE (user_id, business_id);
INSERT IGNORE INTO business_users SELECT * FROM tmp;
DROP TABLE tmp;

上述答案基于this answer。有关外键的警告就像上面一节中所做的那样适用。

一次性移除

如果您只想执行单个查询,而不以任何方式修改表结构,并且您有一个主键id标识每一行,那么您可以尝试以下操作:

DELETE FROM business_users WHERE id NOT IN
    (SELECT MIN(id) FROM business_users GROUP BY user_id, business_id);

this answer之前曾提出类似的想法。

如果上述请求失败,因为您不允许在同一步骤中从表中读取和删除,您可以再次使用临时表:

CREATE TEMPORARY TABLE tmp
SELECT MIN(id) id FROM business_users GROUP BY user_id, business_id;
DELETE FROM business_users WHERE id NOT IN (SELECT id FROM tmp);
DROP TABLE tmp;

如果您愿意,在以这种方式清理数据后仍然可以引入唯一性约束。为此,请执行上一节中的ALTER TABLE行。

答案 1 :(得分:3)

由于您有一个主键,您可以使用它来选择要保留的行:

delete from business_users
where id not in (
    select id from (
        select min(id) as id -- Make a list of the primary keys to keep
        from business_users
        group by user_id, business_id -- Group by your duplicated row definition
    ) as a -- Derived table to force an implicit temp table
);

通过这种方式,您不需要创建/删除临时表等(implicit one除外)。

您可能希望在user_id, business_id上添加一个唯一约束,这样您就不必再担心这个问题了。