удалить повторяющиеся строки на основе условий для других столбцов - PullRequest
0 голосов
/ 06 июля 2018

У меня есть такая таблица:

ID       | CODE     | DATE
1        | 2398     | 2016-4-3   
1        | null     | 2015-8-3   
2        | 1942     | 2015-9-8   
3        | 6752     | 2013-2-1   
3        | 7217     | 2015-1-1   
4        | 9827     | 2011-2-9

в "ID" есть дубликаты, и я хочу удалить строку дубликатов на основании следующих условий:

  1. Если один из «КОДОВ» содержит ноль, сбросьте ноль.
  2. Если оба кода содержат действительный код, сохраните тот, который содержит самую последнюю дату.
  3. Если оба содержат ноль, сохраните тот с самой последней датой.

Желаемый вывод выглядит так:

ID       | CODE     | DATE
1        | 2398     | 2016-4-3     
2        | 1942     | 2015-9-8      
3        | 7217     | 2015-1-1   
4        | 9827     | 2011-2-9

Я знаю, как отбрасывать дубликаты на основе одного столбца:

WITH CTE AS
(
   SELECT *,
          RN = ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
   FROM dbo.YourTable
)
DELETE FROM CTE
WHERE RN > 1

Но я не знаю, как добавить в моих условиях, кто-то может помочь?

Ответы [ 3 ]

0 голосов
/ 06 июля 2018

Вам просто нужно использовать ORDER BY:

WITH CTE AS (
     SELECT t.*,
            ROW_NUMBER() OVER (PARTITION BY COLUMN
                               ORDER BY (CASE WHEN Code IS NOT NULL THEN 1 ELSE 2 END),  -- valid codes first
                                         DATE DESC
                              ) as seqnum
     FROM dbo.YourTable t
    )
DELETE FROM CTE
WHERE seqnum > 1;

Первая строка, указанная в заказе, будет иметь действительный код (если он существует) и самую последнюю дату.

0 голосов
/ 06 июля 2018

[Postgres не разрешает удалять на CTE]

Просто начните с кодирования для всех трех случаев:


DELETE FROM thistable d
WHERE code IS NULL
        AND EXISTS ( SELECT * FROM thistable x
        WHERE x.id = d.id AND x.code IS NOT NULL
        )
OR code IS NULL
        AND EXISTS ( SELECT * FROM thistable x
        WHERE x.id = d.id AND x.code IS NULL
        AND x.zdate > d.zdate
        )
OR code IS NOT NULL
        AND EXISTS ( SELECT * FROM thistable x
        WHERE x.id = d.id AND x.code IS NOT NULL
        AND x.zdate > d.zdate
        );

Теперь вы можете объединить первые два условия (и возможно даже третий)


DELETE FROM thistable d
WHERE code IS NULL
        AND EXISTS ( SELECT * FROM thistable x
        WHERE x.id = d.id
              -- I Don't think you need this
              -- AND x.code <> d.code
        AND x.zdate > d.zdate
        )
OR code IS NOT NULL
        AND EXISTS ( SELECT * FROM thistable x
        WHERE x.id = d.id AND x.code IS NOT NULL
        AND x.zdate > d.zdate
        );

~

0 голосов
/ 06 июля 2018

Суть запроса ниже состоит в том, чтобы вычислить следующее количество с использованием аналитических функций:

COUNT(*) OVER (PARTITION BY ID) - COUNT(CODE) OVER (PARTITION BY ID)

Это количество будет равно единице для дубликатов, имеющих один и только один код NULL. В большинстве других случаев эта величина будет либо двумя (оба кода NULL), либо нулевой (оба кода не NULL, или только один не NULL код).

Это позволяет нам определить, берем ли мы последнюю запись из одного или дубликата, или мы просто сохраняем код не NULL из пары дубликатов.

WITH cte AS (
    SELECT *,
        ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DATE DESC) rn,
        COUNT(*) OVER (PARTITION BY ID) AS total_cnt,
        COUNT(CODE) OVER (PARTITION BY ID) id_cnt
    FROM yourTable
)

DELETE
FROM cte
WHERE
    (total_cnt - id_cnt <> 1 AND rn > 1) OR
    (total_cnt - id_cnt = 1 AND total_cnt > 1 AND CODE IS NULL);

Демо

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