2016-04-28 2 views
1

Я могу сделать запрос, чтобы получить количество клиентов, которые приезжают в магазин с 18 до 24 лет в месяц и за магазин. Я делаю это так:Как считать случаи в нескольких диапазонах дат в PostgreSQL

select year, month, shop_id, count(birthday) 
from customers 
where birthday 
BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
group by year, month, shop_id; 

Теперь у меня вопрос что делает этот запрос для нескольких диапазонов одновременно.

У меня есть в настоящее время эту схему базы данных:

shop_id | birthday | year | month | 
--------+----------+------+-------- 
567 | 1998-10-10 | 2014 | 10 | 
567 | 1996-10-10 | 2014 | 10 | 
567 | 1985-10-10 | 2014 | 10 | 
234 | 1990-10-10 | 2014 | 10 | 
123 | 1970-01-10 | 2014 | 10 | 
123 | 1974-01-10 | 2014 | 11 | 

И я хотел бы получить что-то вроде этого:

shop_id | year | month | 18 < age < 25 | 26 < age < 35 
--------+------+-------+---------------+------------- 
567 | 2014 | 10 | 2    | 1 
234 | 2014 | 10 | 1    | 0 
123 | 2014 | 10 | 0    | 0 

В первом запросе, он не управляет случай, когда один магазин имеет НЕТ клиентов. Как получить 0, если нет?

Как запросить несколько диапазонов дат одновременно?

+0

Имеют выражения в списке выбора, по одному для каждой возрастной группы. Например. ', count (case when ... then 1 end) как 18_age_25, count (case when ...'. – jarlh

+0

возраст на сегодняшний день? –

ответ

0

Вместо фильтров используют тематические отчеты:

select year, month, shop_id, 
count(case when birthday between <range1> then 1 end) RANGE1, 
count(case when birthday between <range2> then 1 end) RANGE2, 
count(case when birthday between <range3> then 1 end) RANGE3 
from customers 
group by year, month, shop_id; 
+1

Спасибо вам большое! Простой и эффективный. – KillianKemps

0

«Нет строки с нулями» является общей проблемой, с GROUP BY запросов. Решение состоит в том, чтобы сделать ваш FROM любой таблицей, имеющей полный список, а затем сделать LEFT JOIN. Поскольку вы группируетесь по годам и месяцам, вам нужно будет составить полный список лет и месяцев. Вы можете сделать это с generate_series:

SELECT t.t, s.id, COUNT(c.birthday) 
FROM shops s 
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t) 
LEFT OUTER JOIN customers c 
ON  c.shop_id = s.id 
AND  c.birthday 
     BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
AND  c.year = EXTRACT(YEAR FROM t.t) 
AND  c.month = EXTRACT(MONTH FROM t.t) 
GROUP BY t.t, s.id 
ORDER BY s.id, t.t; 

Чтобы получить отсчеты для двух диапазонов дат, вы могли бы сделать то, что @ предлагает mo2, или вы могли бы присоединиться к customers таблице дважды:

SELECT t.t, s.id, COUNT(DISTINCT c1.id), COUNT(DISTINCT c2.id) 
FROM shops s 
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t) 
LEFT OUTER JOIN customers c1 
ON  c1.shop_id = s.id 
AND  c1.birthday 
     BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00' 
AND  c1.year = EXTRACT(YEAR FROM t.t) 
AND  c1.month = EXTRACT(MONTH FROM t.t) 
LEFT OUTER JOIN customers c2 
ON  c2.shop_id = s.id 
AND  c2.birthday 
     BETWEEN '1982-01-01 00:00:00' AND '1992-01-01 00:00:00' 
AND  c2.year = EXTRACT(YEAR FROM t.t) 
AND  c2.month = EXTRACT(MONTH FROM t.t) 
GROUP BY t.t, s.id 
ORDER BY s.id, t.t; 

Обратите внимание, что в оба вопроса: я - SELECT В течение полного дня, а не year и month. Это более гибко, я думаю, но его нужно легко изменить, если хотите.

EDIT: Я понял ваш year и month не день рождения, связанные, но что-то еще, я предполагаю, что дата визита? Поэтому я обновил свой запрос. Если вы проверяете только один месяц за раз, вы можете удалить generate_series и просто ввести целые числа года и месяца непосредственно в условия соединения.

Смежные вопросы