SQL — условие в агрегатной функции при группировании

#sql #postgresql

#sql #postgresql

Вопрос:

таблица 1

 person    | zipcode     | timestamp               | event  | device
--------------------------------------------------|--------|------
amar      | 11111       | 2016-09-28 20:05:03.001 | email  | phone
akbar     | 11111       | 2016-09-28 20:05:03.001 | email  | phone  
antony    | 11111       | 2016-09-28 20:07:03.001 | chat   | pc
amar      | 11111       | 2016-09-28 20:08:03.001 | email  | phone
amar      | 11111       | 2016-09-28 20:08:03.001 | chat   | phone
amar      | 22222       | 2016-09-28 20:09:03.001 | email  | phone
akbar     | 22222       | 2016-09-28 20:10:03.001 | email  | phone  
antony    | 22222       | 2016-09-28 20:10:03.001 | chat   | phone
amar      | 11111       | 2016-09-28 21:05:03.001 | email  | phone
akbar     | 11111       | 2016-09-28 21:05:03.001 | email  | phone  
antony    | 11111       | 2016-09-28 21:07:03.001 | chat   | phone
  

желаемый результат

  person    | total_events | email_events 
 ---------------------------------------
 amar       | 5           | 4
 akbar      | 3           | 3
 antony     | 3           | 0
  

Подумываю использовать group by для этого, как показано ниже — как получить количество событий, где event = 'email' здесь — есть ли способ сделать это без использования подвыборки?

 select
  person
  , count (*) as total_events
from table1
group by person
  

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

1. ... count(*) filter (where event = 'email') as email_events

Ответ №1:

Добавьте условие в CASE инструкцию и оберните его в COUNT aggregate

Попробуйте это

 select
  person
  , count (*) as total_events
  , Count(case when event = 'email' then 1 end) as email_events 
from table1
group by person
  

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

1. Кстати, немного проще: ..., count(nullif(event = 'email', false)) ...

Ответ №2:

Используйте group by вместе с case :

 select person,
       count(*) as total_events,
       sum(case when event = 'email' then 1 else 0 end) as email_events
from table1
group by person;
  

В Postgres вы можете сократить это до:

 select person,
       count(*) as total_events,
       sum( (event = 'email')::int ) as email_events
from table1
group by person;