2009-08-26 7 views
2

DB内の重複レコードを削除しようとしました。唯一の違いは、一意識別子であるPrimaryKeyです。私は約3000のエントリを見ているすべてで、だまされている約1500エントリを持っています。だから私は約60件のエントリを(receivedOn日付に基づいて)断ち、私のコードを実行して30に減らし、OH CRAPは消えました!私が試したコードは次のとおりです。SQLデータベースの重複エントリを削除しようとすると、すべてのレコードが削除されました。何が悪かったのか?

DELETE dupes 
FROM [emailTable] dupes, [emailTable] fullTable 
WHERE (dupes.ReceivedOn > '2009-08-18 23:59:59.999' AND dupes.ReceivedOn < '2009-08-20 00:00:00.000') 
     AND (dupes.emlPath = fullTable.emlPath) 
     AND NOT (dupes.GUID = fullTable.GUID) 

私の目標は重複を削除することです。私は気にしません...しかし、私は2つのエントリのうちの1つがサーバーにとどまる必要があります...誰かが私が間違っていたことについていくつかの光を当てることができますか?

+1

たぶん、あなたはすでにこれをやっているが、私は何も削除またはいずれかの方法で、生産データを変更しません最初にROLLBACKを使用してトランザクション内でクエリが動作することを検証することなく、あなたが正しいと分かったら、ROLLBACKをCOMMITに変更してください。 –

+0

私はそうではありません!おそらく参考になるでしょう。これはどうすればいいですか? – swolff1978

+0

BEGIN TRAN *あなたのコードはここにあります。* ROLLBACK TRAN COMMIT TRANあなたが期待している数字のような行が表示されたら、COMMIT TRANを強調表示して実行してください。 –

答えて

7

これは、2番目のテーブルなしで実行できます。このようなもの:

SELECT * FROM emailTable 
WHERE EXISTS (
    SELECT * FROM emailTable AS t2 
    WHERE t2.emlPath = emailTable.emlPath AND 
    t2.GUID > emailTable.GUID) 

これで、削除しようとしているレコードが表示されます。それは大丈夫だ場合は、それを変更します。

DELETE FROM emailTable 
WHERE EXISTS (
    SELECT * FROM emailTable AS t2 
    WHERE t2.emlPath = emailTable.emlPath AND 
    t2.GUID > emailTable.GUID) 

t2.GUID > emailTable.GUIDはそのemlPathを持つレコードが1つのテーブルに残ることを確認します。

2

サブSELECTを使用して削除を実行してください。結合は削除しないでください。

このようにすると、実際に削除する前に削除するGUIDをプレビューできます。それを行う、それはあなたが間違っていた何最小のGUID

delete from emailTable where GUID in 
    (

    select MIN(dupe.GIUD) from emailTable dupe 
     INNER JOIN emailTable noDupe 
     ON dupe.emlPath=noDupe.emlPath 
      where recievedOn between '2009-8-18' and '2009-8-20' 
       GROUP BY dupe.emlPath 
    ) 
1

を削除します。この離れる

を(それ自身で選択クエリを実行すること)クエリが重複のいずれかを排除するものではないということです。同じパスで別の複製と異なる複製を選択しますが、すべての複製は別の複製とは異なります。あなたがしなければならない何

は、最初の例のために、あなたは維持したい重複を選択することです:

select min(GUID) 
from emailTable 
where ReceivedOn > '...' and ReceivedOn < '...' 
group by emlPath 
having count(*) > 1 

次にあなたがそれら以外のすべての重複を削除します。

+0

私はRANKの使用を提案し、ランクが2の一致IDに参加しようとしていました。 –

+0

@rexem、ランク付けされた値に同調していることに注意してください。代わりにROW_NUMBER()を使用してください。 – JeffO

0

あなたは結合で "="を使用しないでください。つまり、 "AND NOT(dupes.GUID = fullTable.GUID)"重複する行のGUIDが異なる必要があるため、この条件は何も行いません。

より大きい値を使用する必要があります。すなわち

delete from emailTable 
WHERE EXISTS 
(
    SELECT ID FROM emailTable t2 
    WHERE emailTable.GUID > t2.GUID 
    AND emailTable.emlPath= t2.emlPath 
) 
0

私はこれとROW_NUMBER()のための共通テーブル式を使用することを好む:

with cte as (
    select row_number() over (partition by emlPath order by GUID) as eml_no 
     , ReceivedOn 
    from [emailTables]) 
delete from cte 
    where eml_no > 1 
    and ReceivedOn between '2009-08-18 23:59:59.999' AND '2009-08-20 00:00:00.000'; 

それが重複する行が削除され、その上stirctに制御することができますので、私はこれをpreffer。私は第3のものを削除して2つを保つことができます、私は最初のものを保ちたいと思う注文番号を選ぶことができます。

0

これは私がすべての記事の助けのおかげで終わったコードだった:

DELETE A 
    FROM [emailTable] A, [emailTable] B 
    WHERE A.MessageID = B.MessageID 
     AND A.GUID > B.GUID 
関連する問題