2010-01-27 71 views
4

這顯示了我所有的名字,並且恰好具有兩個條目是相同MySQL的重複數據刪除

SELECT `firstname`,`lastname`,COUNT(*) AS Count 
FROM `people` 
GROUP BY `firstname`,`lastname` 
HAVING Count = 2 

姓氏如何變成這個DELETE FROM WHERE用了限制語句只刪除一個的每個條目,並離開另一個。

還好這似乎是辦法的技術我只是打算做一個PHP while循環

+0

您認爲計數可能超過2?或者在你的情況下是不可能的?另外,兩個同名的人可能不是同一個人。 – 2010-01-27 13:16:27

+0

是的,我檢查它只有最多2個副本 – Dasa 2010-01-27 13:17:20

回答

2

您可以創建一個包含每個副本1條記錄的表:然後刪除people表中的所有dup記錄,然後重新插入dup記錄。

-- Setup for example 
create table people (fname varchar(10), lname varchar(10)); 

insert into people values ('Bob', 'Newhart'); 
insert into people values ('Bob', 'Newhart'); 
insert into people values ('Bill', 'Cosby'); 
insert into people values ('Jim', 'Gaffigan'); 
insert into people values ('Jim', 'Gaffigan'); 
insert into people values ('Adam', 'Sandler'); 

-- Show table with duplicates 
select * from people; 

-- Create table with one version of each duplicate record 
create table dups as 
    select distinct fname, lname, count(*) 
    from people group by fname, lname 
    having count(*) > 1; 

-- Delete all matching duplicate records 
delete people from people inner join dups 
on people.fname = dups.fname AND 
    people.lname = dups.lname; 

-- Insert single record of each dup back into table 
insert into people select fname, lname from dups; 

-- Show Fixed table 
select * from people; 
+0

有沒有更簡單的方法? – Dasa 2010-01-27 13:10:43

+0

如果您沒有任何其他字段使記錄在他們的答案中使用唯一(如id),那麼當您擁有真正相同的行時,這是非常直接的方法,而且您不必複製整個桌子。 – 2010-01-27 13:38:35

+0

distinct是一個代價高昂的操作,因爲它需要對錶進行排序以刪除重複的行。所以要小心使用不同的。 – 2010-01-27 14:34:15

1

,如果你有一個主鍵,如ID,你可以這樣做:

delete from people 
where id not in 
(
     select minid from 
     (select min(id) as minid from people 
     group by firstname, lastname) as newtable 
) 

子查詢select min(id)...位爲您提供給定名字,姓氏組合的唯一(基於id)行;然後你刪除所有其他行,即你的重複。你需要你的子查詢包裹由於在MySQL中的錯誤,否則我們可以這樣做:

delete from people 
where id not in 
(
     select min(id) as minid from people 
     group by firstname, lastname 
) 

更好的方式是:

delete people from 
people left outer join 
(
    select min(id) as minid from people 
    group by firstname, lastname 
) people_grouped 
on people.first_name = people_grouped.first_name 
and people.last_name = people_grouped.last_name 
and people_grouped.id is null 

避免子查詢。

+0

你能解釋這個代碼 – Dasa 2010-01-27 13:12:59

+0

「你需要包裝你的子查詢,由於在mysql中的錯誤」:當你用同一個表中的選擇進行刪除時,表應該被鎖定在該查詢並沒有在MySQL中實現。請參閱http://dev.mysql.com/doc/refman/5.0/en/delete.html:'目前,您不能從表中刪除並從子查詢中的同一表中進行選擇。「由於MySQL知道風險,它阻止你做這種類型的查詢。你所做的事情導致MySQL沒有注意到問題,但問題仍然存在。話雖如此,如果沒有其他同時使用的用戶可能會好起來。 – 2010-01-27 13:22:59

0

創建一個新表並在(名,姓)上添加一個唯一鍵。然後將舊錶中的行插入新表中。然後重命名錶格。

mysql> select * from t; 
+-----------+----------+ 
| firstname | lastname | 
+-----------+----------+ 
| A   | B  | 
| A   | B  | 
| X   | Y  | 
+-----------+----------+ 
3 rows in set (0.00 sec) 

mysql> create table t2 like t; 
Query OK, 0 rows affected (0.00 sec) 

mysql> alter table t2 add unique key name(firstname,lastname); 
Query OK, 0 rows affected (0.00 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> insert ignore into t2 select * from t; 
Query OK, 2 rows affected (0.00 sec) 
Records: 3 Duplicates: 1 Warnings: 0 


mysql> select * from t2; 
+-----------+----------+ 
| firstname | lastname | 
+-----------+----------+ 
| A   | B  | 
| X   | Y  | 
+-----------+----------+ 
2 rows in set (0.01 sec) 
+0

這個建議存在一些潛在的問題:如果表之間存在限制,您必須先禁用這些表。即使只有很少的行需要刪除,該方法仍然需要複製(幾乎)整個表。最後,也可能有其他列也沒有在問題中提及,這可能會進一步增加需要複製的數據量。 – 2010-01-27 13:27:50

+0

外鍵約束可能是一個問題。關於複製,我覺得這應該比加入表格更快,即使它正在複製整個表格。如果桌子很大,連接可能比這更貴。我只用這兩個字段來演示它。 – 2010-01-27 13:35:09

+0

這看起來比我的整潔的解決方案。 http://www.justin-cook。COM/WP/2006/12/12 /刪除重複的條目 - 行 - 一個MySQL的數據庫表/ – 2010-01-27 14:35:10