2012-09-18 52 views
3

我们有一个表business_users,其中有一个user_idbusiness_id,我们有重复项。 我该如何编写一个查询来删除除一个以外的所有重复项?删除除一个以外的所有副本

+1

点击相关的问题。几个星期前,当我在寻找这个问题时,我发现了一些想法。我混合并匹配了几个以获得理想的结果。 – MetalFrog

+2

你在这个表上有任何主键或其他唯一约束吗?或者'user_id'和'business_id'是唯一的列,这样整个行都会被复制? – ruakh

+0

看起来像http://stackoverflow.com/questions/672702/how-to-delete-duplicates-in-mysql-table的副本?rq = 1 – cptScarlet

回答

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行。

+0

我喜欢最后一个,但我得到你不能指定目标表'business_users'在FROM子句 – Trace

+0

@Trace更新,我添加了一个版本,应该避免那个问题。 – MvG

+0

只是出于好奇,对于一次删除,为什么第一个例子有'SELECT MIN(id)FROM',第二个例子有'SELECT MIN(id)id FROM'(第二个有两个id)? – Pete

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设置一个唯一约束,因此您不必再担心这一点。

+0

看起来不错,但我得到这个你不能在FROM子句中指定目标表'business_users'进行更新 – Trace

+0

@Trace,抱歉...我更新了在这种情况下在mysql中进行子查询的工作。 –

+0

注意:我读过关于使用子查询的相同建议,但在我自己的测试设置中失败。似乎是因为我创建了'business_users'作为临时表,以便进行测试。在这种情况下,错误是措辞'不能重新打开表:'business_users''这几乎是相同的问题(至少在我眼里),但不能通过引入另一个子查询来避免。 – MvG

相关问题