同じProduct列を持つ2つの異なるレコードがある場合は、いくつかの基準で不要なレコードを選択できます。
CREATE TABLE victims AS
SELECT MAX(entryDate) AS date, Product, COUNT(*) AS dups FROM ProductsTable WHERE ...
GROUP BY Product HAVING dups > 1;
次に、ProductTableとVictimsの間でDELETEJOINを実行できます。
または、[製品のみ]を選択してから、他のJOIN条件(たとえば、無効なCustomerId、EntryDate NULLなど)に対してDELETEを実行することもできます。これは、Productの有効なコピーが1つだけあり、他のすべてが無効なデータによって認識できることがわかっている場合に機能します。
代わりに、同一のレコードがあるとします(または、同一と非同一の両方があるか、一部の製品に複数の重複があり、どちらかわからない場合があります)。まったく同じクエリを実行します。次に、ProductsTableでSELECTクエリを実行し、重複排除する製品コードに一致するすべての製品をSELECT DISTINCTして、製品ごとにグループ化し、すべてのフィールドに適切な集計関数を選択します(同一の場合は、どの集計でもかまいません。それ以外の場合は、通常、MAXを試します。またはMIN)。これにより、製品ごとに1行だけが「保存」されます。
その時点で、DELETE JOINを実行し、複製されたすべての製品を強制終了します。次に、保存して重複排除したサブセットをメインテーブルに再インポートするだけです。
もちろん、DELETEJOINとINSERTSELECTの間では、DBが不安定な状態になり、少なくとも1つの重複があるすべての製品が単に消えてしまいます。
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;
次に、製品の行が1つしかない場合は、すべてが良好で、選択されます。それ以上ある場合は、(FieldWhichShouldNeverBeNull IS NULL)がFALSEであるもの(つまり、FieldWhichShouldNeverBeNullが実際にはnullではないもの)が最初に選択され、挿入されます。他のすべての製品は、IGNORE条項により、製品の独自性に反して静かに跳ね返ります。それを行うのは本当にきれいな方法ではありませんが(そして、節でtrueとfalseを混ぜていないことを確認してください!)、それは機能するはずです。
実際にもっと新しい答えを編集する
これは問題を説明するための簡単な表です
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' );
インデックスはまだなく、主キーもありません。それでも、Productを主キーとして宣言できます。
しかし、何か悪いことが起こります。2つの新しいレコードが入り、両方ともNULLの説明があります。
しかし、これまでCBPD14について何も知らなかったため、2つ目は有効な製品であり、この記録を完全に失いたくはありません。ただし、偽のCBPD10を削除したいと思います。
INSERT INTO ProductTable VALUES ( 'CBPD10', NULL );
INSERT INTO ProductTable VALUES ( 'CBPD14', NULL );
失礼なDELETEFROMProductTable WHERE Description IS NULLは問題外であり、重複していないCBPD14を強制終了します。
だから私たちはこのようにします。まず、重複のリストを取得します。
SELECT Product, COUNT(*) AS Dups FROM ProductTable GROUP BY Product HAVING Dups > 1;
「悪いレコードのセットごとに少なくとも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;
さらに確認するために、この障害モードを表す2つのレコードを挿入します。今、私は上記のクエリが新しいコードを返すことを期待しています。
INSERT INTO ProductTable VALUES ( "AC5", NULL ), ( "AC5", NULL );
これで、「チェック」クエリは実際に戻ります。
AC5
したがって、Dupsの生成は良さそうです。
次に、無効な重複レコードをすべて削除します。重複する有効なレコードがある場合、何らかの条件が見つからない限り、それらは重複したままになり、1つの「良好な」レコードを区別し、他のすべてのレコードを「無効」と宣言します(説明とは異なるフィールドで手順を繰り返す場合があります)。
しかし、ええ、摩擦があります。現在、テーブルから削除して、サブクエリ(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;
これで、Dupsテーブルに表示されている場合、すべての無効なレコードが削除されます。
したがって、CBPD14レコードは表示されないため、変更されません。CBPD10の「良好な」レコードは、その説明がNULLであることが真実ではないため、変更されません。他のすべて-poof。
レコードに有効なレコードがなくても重複して いる場合、そのレコードのすべてのコピーが強制終了され、生存者は存在しません。
これを回避するには、最初にこの失敗モードを表す行を別のTEMPORARY TABLEにSELECT(上記のクエリを使用して「何も返さない」チェック)し、削除後にメインテーブルに挿入し直します(トランザクションを使用すると、順番に)。