2013-08-01 199 views
4

我正在處理一個MYSQL數據庫,它有以下三列:電子郵件,姓名,姓氏。MYSQL重複刪除重複行並刪除重複行數據最少

我需要做的就是重複數據刪除,我知道我可以使用的功能,如這一個(這個查詢只是排序未刪除)的郵件:

select distinct emails, name, surname from emails; 

select emails, name, surname from emails group by emails having count(*) >= 2; 

不過,我還需要確保在發現重複的電子郵件地址時,保留的電子郵件地址是具有名稱和/或姓氏值的電子郵件地址。

例如:

| id |電子郵件                            |名稱|姓氏
| 1 | [email protected] |鮑勃        |保爾森      |
| 2 | [email protected] |                       |                                   |

在這種情況下,我想保留第一個結果並刪除第二個。

我一直在尋找使用'案例'或'如果'的陳述,但沒有經驗與使用這些。我試圖用這些陳述擴展上述功能,但無濟於事。

任何人都可以指向正確的方向嗎?

PS:表中的第一列是自動增加一個ID值,如果可以幫助

更新1:下面到目前爲止@Bohemian答案是偉大的工作,但在一種情況下發生故障,其中有一個重複電子郵件地址在一行中有一個名字,但沒有姓,在下一行它沒有名字,但有一個姓。它將保留這兩個記錄。所有需要編輯的內容都是爲了讓這兩個記錄中的一個被刪除,不管是哪一個。

更新2:@波希米亞的答案很好,但經過更多測試後,我發現它存在一個根本性的缺陷,它只在存在重複的電子郵件行時名稱和姓氏字段有數據上表中的第一項)。如果電子郵件重複,但所有行都沒有填寫名稱和姓氏字段,則所有這些行都將被忽略,並且不會進行重複數據刪除。

此查詢的最後一步是找出如何刪除不符合當前必要條件的重複項。如果一行只有名字而另一行只是姓氏,那麼刪除它並不重要,因爲電子郵件是重要的事情。

+1

當一行有名字和下一個姓氏時需要做什麼? –

+0

這是你打算定期做的事情,還是隻是一次性修復? – martin

+0

在這種情況下,我會認爲最好的解決方案是將兩者連接起來,儘管我認爲這會使問題變得複雜。 – psychedelus

回答

3

您可以使用此DELETE查詢,這是通用的,可以很容易地適應以支持更多的領域:

DELETE tablename.* 
FROM 
    tablename LEFT JOIN (
    SELECT MIN(id) min_id 
    FROM 
     tablename t INNER JOIN (
     SELECT 
      emails, MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
     FROM 
      tablename 
     GROUP BY 
      emails) m 
     ON t.emails=m.emails 
     AND ((t.name IS NOT NULL) + (t.surname IS NOT NULL))=m.max_non_nulls 
    GROUP BY 
     t.emails) ids 
    ON tablename.id=ids.min_id 
WHERE 
    ids.min_id IS NULL 

請參閱小提琴here

該查詢返回非空字段的最大數目,每封電子郵件:

SELECT 
    emails, 
    MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
FROM 
    tablename 
GROUP BY 
    emails 

然後我加入這個查詢與表名,獲得最小的ID爲擁有最大數量的每封電子郵件非空字段:

SELECT MIN(id) min_id 
FROM 
    tablename t INNER JOIN (
    SELECT 
     emails, MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
    FROM 
     tablename 
    GROUP BY 
     emails) m 
    ON t.emails=m.emails 
    AND ((t.name IS NOT NULL) + (t.surname IS NOT NULL))=m.max_non_nulls 
GROUP BY 
    t.emails 

然後我刪除所有具有此查詢未返回的ID的行。

+0

非常感謝你,查詢完美地工作。也很感謝你採取的步驟的解釋,它有很大的幫助。任何方式,我可以捐贈給你一杯啤酒? – psychedelus

4

這是很容易與MySQL的multiple-table delete syntax

delete b 
from mytable a 
join mytable b 
    on a.email = b.email 
    and a.id != b.id 
where a.name is not null 
and a.surname is not null 
+1

非常感謝@Bohemian,查詢效果很好。唯一不起作用的情況是,一行中有重複的電子郵件有名字而沒有姓,另一行沒有名字但有一個用戶名。在這種情況下,兩者都保留。在這種情況下,保存的內容並不重要,但必須去做。 – psychedelus

+0

是的,這裏有一個輕微的邏輯錯誤 - 但它很容易修復;-) – Strawberry

+1

@Strawberry你願意分享你想要的修復嗎? – psychedelus

0

刪除記錄重複的電子郵件ID

delete 
    from duplicate_email where id in(
     select id from (
      select id, email from duplicate_email group by email having count(id) > 1) as id 
    ) 

,但有一個問題,你可以刪除那些只有一個重複的電子郵件即,兩個相同的電子郵件,但如果有三個或更多,你可以重複記錄這個查詢,直到你得到零記錄刪除