2012-03-14 8 views
1

次のクエリを使用してデータベースに重複エントリを表示しています(誤ってスクリプトを2回実行したようですが、悪意のあるユーザーであった可能性があります)。重複している場合、MySQL DBから行を削除する

それは実際に私の要件を満たしていませんが、私は、次のクエリを使用しています:

SELECT meta_value, COUNT(meta_value) AS cnt 
FROM wp_postmeta 
GROUP BY meta_value 
HAVING cnt > 1 
ORDER BY cnt; 

私は重複したエントリが同じpost_idmeta_keyを持っているかどうかを確認するために、クエリたいと思います。

ので、例えば:

meta_id  post_id  meta_key meta_value 
1   10   size  large 
2   10   colour  blue 
3   10   size  large 
4   11   size  large 

meta_id 1と3は、重複したエントリです。

私はこのようなエントリのすべてを削除したいと思います。

1つのクエリでこれを行う方法はありますか?クエリが期待どおりに行えることを確認するために行を最初に見ることができれば、それは素晴らしいことです。事前に

おかげで、

+0

[テーブルから重複する行を削除する]可能性のある複製(http://stackoverflow.com/questions/1043488/deleting-duplicate-rows-from-a-table) –

+1

最初に重複を取得した理由を見つけてください! – Har

答えて

4

はこれを試してみてください - あなたが削除されている行への参照について@ RolandBoumanの警告の

DELETE t2 
FROM wp_postmeta t1 
INNER JOIN wp_postmeta t2 
    ON t1.post_id = t2.post_id 
    AND t1.meta_key = t2.meta_key 
    AND t1.meta_value = t2.meta_value 
    AND t1.meta_id < t2.meta_id 

をメモします。

+0

私は訂正した。素晴らしい解決策! –

+0

@RolandBouman - 2番目のテーブルエイリアスを修正していただきありがとうございます。 – nnichols

+0

美しい - 私が書いたものよりも良い方法がありました - 私はその時それを考えることができませんでした。完璧! – user158017

0

私がテストしていませんが、このような何かが動作するはずです(これはあなたのselect文は、あなたはそれが何をしたいグラブを前提とし)

DELETE FROM wp_postmeta 
WHERE meta_id IN (
       SELECT meta_id 
       FROM wp_postmeta 
       GROUP BY meta_value 
       HAVING COUNT(meta_value) > 1 
       ORDER BY cnt 
       ); 
1

EDIT:nnichols答えは方法ですより良い。


このようなことを試してみてください - より効率的な方法があるかもしれませんが、私の頭の上からはうまくいくようです。

delete from wp_postmeta 
where meta_id in 
(select meta_id 
from 
    (select meta_key, meta_value, post_id 
     from wp_postmeta 
     group by meta_key, meta_value, post_id 
     having count(*) > 1) problemGroups 
inner join wp_postmeta a 
     on a.meta_key = problemGroups.meta_key 
     and a.meta_value = problemGroups.meta_value 
     and a.post_id = problemGroups.post_id) allIDs 
and meta_id not in 
(select min(meta_id) 
from 
    (select meta_key, meta_value, post_id 
     from wp_postmeta 
     group by meta_key, meta_value, post_id 
     having count(*) > 1) problemGroups 
inner join wp_postmeta a 
     on a.meta_key = problemGroups.meta_key 
     and a.meta_value = problemGroups.meta_value 
     and a.post_id = problemGroups.post_id 
group by problemGroups.meta_key, meta_value, port_id) minIDS 
2

"重複するエントリに同じpost_idとmeta_keyがあるかどうかを確認するクエリも必要です。"

次に、グループ内の値も同様に使用します。

SELECT meta_value, COUNT(meta_value) AS cnt 
FROM wp_postmeta 
GROUP BY post_id, meta_key, meta_value 
HAVING cnt > 1 
ORDER BY cnt; 

"このようなエントリのうち1つだけを削除したいと思います。"

これは残念ながらMySQLでは簡単ではありません。 (http://dev.mysql.com/doc/refman/5.5/en/delete.htmlを参照してください)

マルチテーブルの削除構文と呼ばれるものがありますが、削除するテーブルと同じテーブルに参加する必要がある場合は無駄です。サブクエリを使用すると、削除しているテーブルと同じテーブルから選択することはできないため、飛行しません。

残念ながらこれを行う最も簡単な方法は、クエリによってグループに基づいて一時テーブルを作成し、に参加するためにそれを使用することです:あなたは一時テーブルを破棄することができ、行を削除した後

CREATE TABLE wp_postmeta_delete 
AS 
SELECT MIN(meta_id) meta_id 
,  post_id 
,  meta_key 
,  meta_value 
FROM wp_postmeta 
GROUP BY post_id, meta_key, meta_value 
HAVING count(*) > 1; 

DELETE  wp_postmeta.* 
FROM  wp_postmeta 
INNER JOIN wp_postmeta_delete t2 
ON   wp_postmeta.meta_id != t2.meta_id 
AND  wp_postmeta.post_id = t2.post_id 
AND  wp_postmeta.meta_key = t2.meta_key 
AND  wp_postmeta.meta_value = t2.meta_value; 

DROP TABLE wp_postmeta_delete; 

多くの場合、重複を削除するだけでは十分ではないことがあります。他のテーブルが重複行を指している場合は、それらの参照を移行して、対応する一意の行をポイントする必要があります。

+0

簡単な自己結合ではるかに簡単です。 – nnichols

+0

@nncicholsので、SQLを見せてください。最初の投稿のコンテキストなので、MySQLで最初に試してみてください。 –

+1

私はここに私の答えに掲載しています。 – nnichols

関連する問題