SQL — Фильтр повторяющихся строк с разными значениями в одном столбце

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я сталкиваюсь с проблемой, когда необходимо отфильтровывать повторяющиеся строки, ограничивая некоторые критерии для другого столбца, например, отфильтровывать строки, дублируемые MappingID Date столбцами и , но для столбца должно быть как значение NULL, так и значение NOT NULL Subject .

Исходные данные:

 | Subject      | MappingID | Date       | Qty    | 
 -------------- ----------- ------------ -------- 
| NULL         | M1        | 2020-11-01 |  10    | 
| S1           | M1        | 2020-11-01 |  20    | 
| S2           | M2        | 2020-11-01 |   5    |
| S2           | M2        | 2020-11-01 |   6    |
| NULL         | M1        | 2020-11-02 |   7    |  
 

Ожидаемый результат ( Subject сводный, M2 не включен в набор результатов, поскольку тема одна и та же) :

 | MappingID | Date       | Subject1 | Subject2 | Subject1Qty | Subject2Qty |
 ----------- ------------ ---------- ---------- ------------- ------------- 
| M1        | 2020-11-01 | S1       | NULL     |     20      |     10      |
 

Комментарии:

1. Вы не можете произвольно выполнять поворот в T-SQL: вам необходимо предварительно определить имена сводных столбцов. Но еще лучше вообще не сводить. Вам обязательно нужно сводить результирующие данные?

2. Может ли a mapping_id иметь более двух объектов в одном и том же day , например NULL, S1, S2 ? Если да, то каковы ограничения и каковы ваши ожидаемые результаты для такого сценария?

3. Может ли a mapping_id иметь несколько строк для одного и того же объекта в одном и том же day и при этом соответствовать другим вашим критериям? Например NULL, NULL, S1, S1 ? Если да, то каковы ваши ожидаемые результаты для такого сценария?

4. @Dai Мне нужно сравнить эти NULL и NOT NULL Subject, есть ли у вас какие-либо другие предложения, если не использовать pivot?

5. @MatBailie, да, может быть более двух объектов, для тех, которые не являются нулевыми, мы можем объединить их как один

Ответ №1:

Используйте group by и having :

 select mappingid, date,
    max(case when rn = 1 then subject end) as subject1,
    max(case when rn = 2 then subject end) as subject2,
    max(case when rn = 1 then qty     end) as qty1,
    max(case when rn = 2 then qty     end) as qty2
from (
    select t.*, 
        row_number() over(partition by mappingid, date order by subject) rn
    from mytable t
) t
group by mappingid, date
having max(subject) is not null 
   and max(case when subject is null then 1 else 0 end) = 1
 

Ответ №2:

На самом деле вы можете сделать это без подзапроса — при условии, что у вас есть две строки для каждого идентификатора и даты:

 select mappingid, date,
       max(subject) as subject_1,
       max(case when subject is not null then qty end) as qty_1,
       null as subject_2,
       max(case when subject is null then qty end) as qty_2
from t
group by mappingid, date
having count(subject) = 1 and count(*) = 2;