Попытка удалить дубликаты записей в базе данных SQL удалила все записи. Что пошло не так? - PullRequest
2 голосов
/ 26 августа 2009

Я пытался удалить дубликаты записей в моей БД. Единственное отличие - это PrimaryKey, который является уникальным идентификатором. У меня есть около 1500 записей, которые были дублированы, поэтому я смотрю около 3000 записей. Таким образом, я разделил около 60 записей (на основе даты получения) и выполнил мой код, чтобы уменьшить их до 30, а ОХ СЛУЧАЙНЫЕ 30 исчезли! Вот код, который я пробовал:

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)

Моя цель - удалить дубликаты. Мне все равно, какой ... но мне нужна ОДНА из двух записей, чтобы остаться на сервере ... Кто-нибудь может пролить свет на то, что я сделал неправильно?

Ответы [ 6 ]

7 голосов
/ 26 августа 2009

Вы можете сделать это без второй таблицы. Примерно так:

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 голосов
/ 26 августа 2009

Удаление следует выполнять с помощью подвыбора, а не объединения.

Преимущество такого способа заключается в том, что вы можете предварительно просмотреть 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 голос
/ 26 августа 2009

Что вы сделали неправильно, так это то, что ваш запрос не исключает дубликатов. Он выбирает дубликаты, которые отличаются от другого дубликата с тем же путем, но каждый дубликат отличается от другого дубликата.

Что вам нужно сделать, это сначала выбрать дубликаты, которые вы хотите сохранить, например:

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

Затем вы удаляете все дубликаты, кроме этих.

0 голосов
/ 27 августа 2009

Это код, к которому я пришел благодаря помощи всех постов:

DELETE A
  FROM [emailTable] A, [emailTable] B
  WHERE A.MessageID = B.MessageID
        AND A.GUID > B.GUID
0 голосов
/ 27 августа 2009

Я предпочитаю использовать общее табличное выражение для этого и 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';

Я предпочитаю это, потому что это дает возможность контролировать, какая дублирующаяся строка удаляется. Я могу удалить третий и оставить два, я могу выбрать любой номер ордера, который я хочу сохранить, первый, и он отлично работает со связями.

0 голосов
/ 26 августа 2009

Вы не должны использовать «=» в своем соединении. то есть "И НЕ (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
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...