Удалить дубликаты из набора записей, исключая столбцы из условия дублирования - PullRequest
0 голосов
/ 04 декабря 2009

Я использую базу данных mssql с SQL-запросом вроде ...

SELECT id, type, start, stop, one, two, three, four
FROM a
UNION ALL
SELECT id, type, start, stop, one, two, three, four
FROM b
UNION ALL
SELECT id, type, start, stop, one, two, three, four
FROM c
ORDER BY type ASC

В результате ...

row |  id  type  start       stop         one   two    three   four
----+--------------------------------------------------------------
 1  |  1   a     2010-01-01  2010-01-31   100   1000   1000    100
 2  |  1   a     2010-02-01  2010-12-31   100   500    500     50
 3  |  1   b     2010-01-01  2010-01-31   100   NULL   NULL    100
 4  |  1   b     2010-01-01  2010-12-31   100   NULL   NULL    100
 5  |  1   c     2010-01-01  2010-01-31   0     NULL   NULL    100
 6  |  1   c     2010-01-01  2010-12-31   0     NULL   NULL    100

Однако я бы предпочел следующий результат ...

row |  id  type  start       stop         one   two    three   four
----+--------------------------------------------------------------
 1  |  1   a     2010-01-01  2010-01-31   100   1000   1000    100
 2  |  1   a     2010-02-01  2010-12-31   100   500    500     50
 4  |  1   b     2010-01-01  2010-12-31   100   NULL   NULL    100
 6  |  1   c     2010-01-01  2010-12-31   0     NULL   NULL    100

То есть, исключая строки 3 и 5, поскольку они являются однотипными для строк 4 и 6 во всех отношениях , но столбец stop , в то время как несчастная строка имеет самый низкий значение в исключающем столбце stop должно быть удалено.

Как я могу это сделать? Я думал что-то вроде ...

SELECT * FROM (
    SELECT id, type, start, stop, one, two, three, four
    FROM a
    UNION ALL
    SELECT id, type, start, stop, one, two, three, four
    FROM b
    UNION ALL
    SELECT id, type, start, stop, one, two, three, four
    FROM c
    ORDER BY type ASC
) AS types
GROUP BY ... HAVING ???

Мне нужно руководство, пожалуйста, помогите.

(И нет, я не в состоянии изменить какие-либо условия, я должен работать с данной ситуацией.)

Ответы [ 2 ]

1 голос
/ 04 декабря 2009

Подобные вопросы были заданы и даны ответы. Например: Выберите уникальные, и один из двойников

И ваша ситуация еще проще (если я правильно понял описание вашей проблемы):

select id, type, start, max(stop), one, two, three, four
    from (...) types
    group by id, type, start, one, two, three, four
    order by ...

Вместо (...) вы делаете выбор из a, b и c. Просто пропустите пункт order by.

Или, если вместо (id, type, start) -> (один, два, три, четыре) у вас есть (id, type, start, stop) -> (один, два, три, четыре) (значение Вы должны выбрать другие столбцы, которые соответствуют до max (stop)), этот запрос обычно приводит к разумному плану выполнения:

select id, type, start, stop, one, two, three, four
    from (...) types
    where stop = (select max(stop)
                  from (...) t2
                  where t2.id = types.id
                        and t2.type = types.type
                        and t2.start = types.start)

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

1 голос
/ 04 декабря 2009

Это должно работать:

SELECT
     id,
     type,
     start,
     stop,
     one,
     two,
     three,
     four
FROM
     A T1
LEFT OUTER JOIN A T2 ON
     T2.id = T1.id AND
     T2.type = T1.type AND
     T2.start = T1.start AND
     T2.one = T1.one AND
     ...
     T2.stop > T1.stop
WHERE
     T2.id IS NULL     -- This must be a NOT NULL column for this to work

Это предполагает, что столбец типа имеет то же значение, что и имена таблиц, как в ваших примерах. Если у вас могут быть дублирующиеся строки между таблицами, вам нужно будет выполнить ту же логику, используя подзапрос того, что у вас есть вместо A. Если мое предположение верно, то просто замените каждый из трех запросов UNION ALL на приведенный выше, изменив имена таблиц.

Идея состоит в том, что если существует строка, которая соответствует, но с более поздней датой остановки, то вы не хотите включать строку в результаты. Используя LEFT OUTER JOIN, единственный способ, которым T2.id будет NULL, - это если бы такого совпадения не было, поэтому мы можем включить его в набор результатов (поэтому id должен быть столбцом NOT NULL, чтобы это работало.)

Поскольку вы сказали, что не можете изменить БД, я избавлю вас от выговора "этот дизайн отстой";)

...