2009-08-26 72 views
2

我試圖刪除我的數據庫中的重複記錄。唯一的區別是PrimaryKey是唯一標識符。我有大約1500個參賽作品被欺騙了,所以我在看3000場參賽作品。所以我分了大約60個條目(根據收到的日期),並執行我的代碼,將它們削減到30,OH CRAP 30消失了!這裏是我試過的代碼:試圖刪除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) 

我的目標是刪除重複。我不在乎哪一個......但我需要兩個條目之一留在服務器上......任何人都可以闡明我做錯了什麼?

+1

也許你已經這樣做了,但我不會刪除任何東西,或以任何方式修改生產數據而無需首先驗證查詢在具有ROLLBACK的事務中的效果。當你知道你是對的,將ROLLBACK改爲COMMIT。 – 2009-08-26 19:52:33

+0

我不是!這可能會有所幫助。我該怎麼做呢? – swolff1978 2009-08-26 20:01:01

+0

BEGIN TRAN *您的代碼在這裏* ROLLBACK TRAN COMMIT TRAN當受影響的行看起來像您期望的數字時,突出顯示COMMIT TRAN並執行它。 – 2009-08-26 20:05:03

回答

7

您可以在沒有第二個表的情況下執行此操作。類似這樣的:

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將保留在表中。

2

您應該使用子選擇而不是連接進行刪除。

這樣做的好處是,您可以在實際刪除它們之前預覽要刪除的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。 – 2009-08-26 19:39:16

+0

@rexem,小心在排名的值中取平行。改用ROW_NUMBER()。 – JeffO 2009-08-26 20:03:41

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'; 

我preffer這一點,因爲它給了stirct控制哪些重複行被刪除。我可以刪除第三個並保留兩個,我可以選擇任何我想保留第一個的訂單號碼,並且它可以很好地處理關係。

0

這是我結束了在感謝所有帖子的幫助下,代碼:

DELETE A 
    FROM [emailTable] A, [emailTable] B 
    WHERE A.MessageID = B.MessageID 
     AND A.GUID > B.GUID