SQL - Группировать две строки по столбцам, которые имеют значение и null в разных столбцах. - PullRequest
1 голос
/ 10 июля 2020

Вопрос

Допустим, у меня есть таблица с такими строками:

id | country | place | last_action | second_to_last_action
----------------------------------------------------------
1  |   US    |   2   |   reply     | 
1  |   US    |   2   |             |       comment
4  |   DE    |   5   |   reply     | 
4  |         |       |             |       comment

Я хочу объединить их по идентификатору, стране и месту, чтобы last_action и second_to_last_action быть в одном ряду

id | country | place | last_action | second_to_last_action
----------------------------------------------------------
1  |   US    |   2   |   reply     |      comment
4  |   DE    |   5   |   reply     |      comment

Как мне подойти к этому? Думаю, здесь мне понадобится агрегат, но я не могу понять, какой из них использовать.

Можно ожидать, что всегда будет подходящая пара.

Справочная информация:

Примечание: эта таблица была получена из чего-то вроде этого:

id | country | place |   action    | time
----------------------------------------------------------
1  |   US    |   2   |   reply     |    16:15
1  |   US    |   2   |   comment   |    15:16
1  |   US    |   2   |   view      |    13:16
4  |   DE    |   5   |   reply     |    17:15
4  |   DE    |   5   |   comment   |    16:16
4  |   DE    |   5   |   view      |    14:12

Код, используемый для разделения, был:

row_number() over (partition by id order by time desc) as event_no

И затем я получил действия last и second_to_last получая event_no 1 и 2. Поэтому, если есть более эффективный способ получить последние два действия в двух разных столбцах, я был бы рад это услышать.

1 Ответ

1 голос
/ 10 июля 2020

Вы можете исправить свои первые данные, используя агрегирование:

select id, country, place, max(last_action), max(second_to_last_action)
from derived
group by id, country, place;

Вы можете сделать это из исходной таблицы, используя условное агрегирование:

select id, country, place,
       max(case when seqnum = 1 then action end) as last_action,
       max(case when seqnum = 2 then action end) as second_to_last_action
from (select t.*,
            row_number() over (partition by id order by time desc) as seqnum
      from t
     ) t
group by id, country, place;
...