2012-09-18 57 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

相關問題