如果您有兩個具有相同產品列的不同記錄,那麼您可以使用某些標準選擇不想要的記錄,例如,
CREATE TABLE victims AS
SELECT MAX(entryDate) AS date, Product, COUNT(*) AS dups FROM ProductsTable WHERE ...
GROUP BY Product HAVING dups > 1;
然後,您可以在ProductTable和受害者之間執行DELETE JOIN。
或者您也可以選擇僅產品,然後對其他JOIN條件執行DELETE,例如具有無效的CustomerId或EntryDate NULL或其他任何其他條件。如果你的知道有一個且只有一個有效的產品副本,並且所有其他產品都可以通過無效數據識別,那麼這將起作用。
假設你改爲擁有IDENTICAL記錄(或者你有兩個完全相同或不相同的產品,或者對於某些產品你可能有幾個產品,你不知道是哪一個產品)。您運行完全相同的查詢。然後,在ProductsTable和SELECT DISTINCT上運行SELECT查詢,所有匹配要被重複刪除的產品代碼的產品,按產品分組,以及爲所有字段選擇合適的聚合函數(如果相同,則聚合應該執行;否則,我通常嘗試使用MAX或MIN)。這將爲每個產品「精確保存」一行。
此時您運行DELETE JOIN並殺死所有重複的產品。然後,只需將保存的和重複的子集重新導入主表。
當然,在DELETE JOIN和INSERT SELECT之間,您將使DB處於不穩定狀態,並且至少有一個重複的所有產品都會消失。
另一種方式應在MySQL的工作:
-- Create an empty table
CREATE TABLE deduped AS SELECT * FROM ProductsTable WHERE false;
CREATE UNIQUE INDEX deduped_ndx ON deduped(Product);
-- DROP duplicate rows, Joe the Butcher's way
INSERT IGNORE INTO deduped SELECT * FROM ProductsTable;
ALTER TABLE ProductsTable RENAME TO ProductsBackup;
ALTER TABLE deduped RENAME TO ProductsTable;
-- TODO: Copy all indexes from ProductsTable on deduped.
注意:以上的方式不起作用如果要區分「好記」和「無效的重複」。它只適用於你有冗餘DUPLICATE記錄,或者如果你不在乎哪你保留的行和你丟棄!
編輯: 你說「重複」有無效的字段。在這種情況下,你可以修改上面分揀招:
SELECT * FROM ProductsTable ORDER BY Product, FieldWhichShouldNotBeNULL IS NULL;
那麼,如果你只有一排產品,一切都很好,它會被選中。如果你有更多的,那麼(FieldWhichShouldNeverBeNull IS NULL)是FALSE的那個(也就是FieldWhichShouldNeverBeNull實際上不應該爲null的那個實際上不應該是null)將被首先選擇並被插入。所有其他人都會因IGNORE條款而無聲地反彈產品的獨特性。不是一個非常好的方式來做到這一點(並檢查我沒有在我的條款中混淆真假),但它應該工作。
編輯
其實更多的新的答案
的這是一個簡單的表來說明問題
CREATE TABLE ProductTable (Product varchar(10), Description varchar(10));
INSERT INTO ProductTable VALUES ('CBPD10', 'C-Beam Prj');
INSERT INTO ProductTable VALUES ('CBPD11', 'C Proj Mk2');
INSERT INTO ProductTable VALUES ('CBPD12', 'C Proj Mk3');
沒有指數着呢,沒有主鍵。我們仍然可以將產品聲明爲主鍵。
但是發生了一些不好的事情。兩個新記錄進入,並且都有NULL描述。
然而,第二個是有效的產品,因爲在此之前我們對CBPD14一無所知,因此我們不希望完全失去此記錄。我們做雖然想擺脫虛假的CBPD10。
INSERT INTO ProductTable VALUES ('CBPD10', NULL);
INSERT INTO ProductTable VALUES ('CBPD14', NULL);
粗魯DELETE從ProductTable WHERE描述IS NULL是不可能的,它會殺死CBPD14這是不重複的。
所以我們這樣做。首先得到重複列表:
SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1;
我們假設:「每組壞記錄至少有一個好記錄」。
我們通過設定相反的方向並查詢它來檢查這個假設。如果所有都是協同的,我們期望這個查詢不返回任何內容。
SELECT Dups.Product FROM ProductTable
RIGHT JOIN (SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1) AS Dups
ON (ProductTable.Product = Dups.Product
AND ProductTable.Description IS NOT NULL)
WHERE ProductTable.Description IS NULL;
爲了進一步驗證,我插入了代表這種失敗模式的兩條記錄;現在我確實希望上面的查詢返回新的代碼。
INSERT INTO ProductTable VALUES ("AC5", NULL), ("AC5", NULL);
現在的 「檢查」 查詢確實返回,
AC5
所以,複本的產生看起來不錯。
我現在着手刪除所有不是有效的重複記錄。如果有重複的有效記錄,除非發現一些條件,否則它們將保持複製狀態,在它們之間區分一個「良好」記錄並聲明所有其他記錄「無效」(可能重複該過程的字段與描述不同)。
但是,有一個問題。 目前,您無法從表中刪除並從子查詢(http://dev.mysql.com/doc/refman/5.0/en/delete.html)中的同一表中進行選擇。因此,需要一點點的解決方法:
CREATE TEMPORARY TABLE Dups AS
SELECT Product, COUNT(*) AS Duplicates
FROM ProductTable GROUP BY Product HAVING Duplicates > 1;
DELETE ProductTable FROM ProductTable JOIN Dups USING (Product)
WHERE Description IS NULL;
現在這將刪除所有無效的記錄,只要他們出現在複本表。
因此,我們的CBPD14記錄將保持不變,因爲它不會出現在那裏。 CBPD10的「良好」記錄將保持不變,因爲它的描述不是NULL。所有其他 - 噗。
再次讓我的狀態,如果一個記錄有沒有有效記錄,但是重複,然後所有副本該記錄的會被殺死 - 不會有幸存者。
爲了避免這種情況,可以先將表示這種失敗模式的行放入另一個臨時表中,然後在刪除後將它們重新插入到主表中(在上面的查詢中,檢查「哪個不應該返回」)使用交易可能是有序的)。
數據庫有多大。我們在這裏談論數百萬行嗎?十億? – 2012-07-15 11:44:10
大約有200,000條記錄,其中有3000個重複,但並不多:D – Sypress 2012-07-15 11:44:54
當您有兩條記錄的產品數據相同但其他列中的數據不同時,您如何知道哪一條是正確的? – 2012-07-15 11:45:37