我们有一个business_users
带有user_id
and的表,business_id
并且我们有重复项。如何编写一个查询来删除除一个之外的所有重复项?
问问题
4254 次
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_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;
上面的答案是基于这个答案。关于外键的警告与上一节一样适用。
一键删除
如果您只想执行单个查询,而不以任何方式修改表结构,并且您有一个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 回答