我们有business_users
和user_id
的表business_id
,我们有重复项。
如何编写将删除除一个重复项以外的所有重复项的查询?
答案 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_id
和business_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
上添加一个唯一约束,这样您就不必再担心这个问题了。