3

我们有一个business_users带有user_idand的表,business_id并且我们有重复项。如何编写一个查询来删除除一个之外的所有重复项?

4

2 回答 2

10

完全相同的行

如果您想避免完全相同的行,正如我最初理解您的问题那样,那么您可以将唯一行选择到单独的表中并从中重新创建表数据。

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

但是,如果有任何外键约束引用此表,请小心,因为临时删除行可能会导致其他地方的级联删除。

引入唯一约束

如果您只关心 and 对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;

上面的答案是基于这个答案。关于外键的警告与上一节一样适用。

一键删除

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

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

这个答案之前提出了类似的想法。

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

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上一节中的行。

于 2012-09-18T18:44:30.150 回答
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
);

这样,您将不需要创建/删除临时表等(隐式表除外)。

您可能想设置一个独特的约束,user_id, business_id这样您就不必再担心这个了。

于 2012-09-18T19:04:45.507 回答