Как я могу оптимизировать этот SQL-запрос для удаления каждой второй повторяющейся строки? - PullRequest
1 голос
/ 26 марта 2019

Мне нужно сохранить только одну строку, в которой дублируется значение, т. Е. Удалить каждую строку, которая не является «первой», с дублированным значением.

У меня есть следующая таблица с именем ART_NEW:

PHARMACODE | GTIN | {Other stuff}
111          1234   ...
  • ФАРМАКОД - это первичный ключ (целое число)
  • GTIN - это другое целое число, предположительно уникальное, но иногда случаются столкновения.

Источник данных для этой таблицы готовится к переходу от PHARMACODE к GTIN в качестве первичного ключа, но этот переход еще не завершен. Я не контролирую источник каким-либо образом.

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

Следующий запрос делает именно то, что мне нужно, но ужасно медленно (> 1 минута выполнения на 350 000 записей с 120 строками с дублирующимися значениями GTIN):

DELETE *
FROM ART_NEW
WHERE ART_NEW.PHARMACODE IN 
    (SELECT PHARMACODE FROM
        (SELECT
            ART_NEW.[PHARMACODE],
            ART_NEW.GTIN,
            (SELECT Count(*)
                FROM ART_NEW As X
                WHERE X.GTIN = ART_NEW.GTIN
                    AND X.PHARMACODE <= ART_NEW.PHARMACODE) AS SeqNo
            FROM ART_NEW
            WHERE ART_NEW.[GTIN] In 
            (SELECT [GTIN] FROM [ART_NEW] As Tmp GROUP BY [GTIN] HAVING Count(*)>1)) 
        WHERE SeqNo > 1);

Как я могу оптимизировать этот код? В качестве альтернативы, есть ли лучший способ достичь моей цели удаления каждой строки, кроме одной с дублирующимися значениями GTIN?

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Если у вас нет первичного ключа в таблице, это простой способ удалить дублирующиеся строки.Установите для параметра PartitionBy значение, которое, по вашему мнению, будет вашим уникальным идентификатором, а ваш порядок - вашим порядком сортировки, в результате чего в верхнем ряду будут ваши действительные данные, а все, что ниже, будет считаться недействительными данными, которые будут удалены.

DELETE a
FROM (
        SELECT 
           ROW_NUMBER() OVER (PARTITION BY tableUniqueid ORDER BY dateCreated DESC) AS SEQ,
           *
        FROM myTable
) a
WHERE SEQ > 1
1 голос
/ 26 марта 2019

похоже, что PHARMACODE является числовым, который должен работать со стандартным SQL:

delete * from ART_NEW 
where ART_NEW.PHARMACODE  NOT IN 
(select a3.PHARMACODE from (select min(a2.PHARMACODE) as PHARMACODE, a2.GTIN from ART_NEW a2 group by a2.GTIN) a3)
;

select * from ART_NEW 
where ART_NEW.PHARMACODE  IN 
(select a3.PHARMACODE from (select min(a2.PHARMACODE) as PHARMACODE, a2.GTIN from ART_NEW a2 group by a2.GTIN) a3)
;

Также, если вы можете использовать разделы, попробуйте сделать Where для row = 1 с OVER(PARTITION BY GTIN).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...