2012-02-24 6 views
1

Я использую Postgresql 9, и я сражаюсь с подсчетом и группировкой, когда никакие строки не подсчитываются.Группировка по дате, с 0, когда count() не дает строк

Давайте предположим следующую схему:

create table views { 
date_event timestamp with time zone ; 
event_id integer; 
} 

Давайте представим себе следующее содержание:

2012-01-01 00:00:05 2 
2012-01-01 01:00:05 5 
2012-01-01 03:00:05 8 
2012-01-01 03:00:15 20 

Я хочу группы по часам, и подсчитать количество строк. Я хотел бы получить следующее:

2012-01-01 00:00:00 1 
2012-01-01 01:00:00 1 
2012-01-01 02:00:00 0 
2012-01-01 03:00:00 2 
2012-01-01 04:00:00 0 
2012-01-01 05:00:00 0 
. 
. 

2012-01-07 23:00:00 0 

Я имею в виду, что для каждого интервала временного диапазона, подсчитать количество строк в моей таблице, дата соответствует, в противном случае, я возвращаю строку со счетчиком на нуле.

Следующие, безусловно, не будут работать (будут спрятать только линии с подсчитанными линиями> 0).

SELECT extract (hour from date_event),count(*) 
FROM views 
where date_event > '2012-01-01' and date_event <'2012-01-07' 
GROUP BY extract (hour from date_event); 

Пожалуйста, обратите внимание, я, возможно, также необходимо сгруппировать по минуту, или час, или день, или месяц, или год (несколько запросов, возможно, конечно).

Я могу использовать простой старый sql, и так как моя таблица просмотров может быть очень большой (> 100M записей), я стараюсь сохранить производительность в памяти.

Как это можно достичь?

Спасибо!

ответ

5

Учитывая, что у вас нет дат в таблице, вам нужен способ их создания. Вы можете использовать generate_series функции:

SELECT * FROM generate_series('2012-01-01'::timestamp, '2012-01-07 23:00', '1 hour') AS ts; 

Это даст результаты, как это:

  ts   
--------------------- 
2012-01-01 00:00:00 
2012-01-01 01:00:00 
2012-01-01 02:00:00 
2012-01-01 03:00:00 
... 
2012-01-07 21:00:00 
2012-01-07 22:00:00 
2012-01-07 23:00:00 
(168 rows) 

Оставшаяся задача состоит в том, чтобы соединить два выбирает с помощью внешнего соединения, как это:

select extract (day from ts) as day, extract (hour from ts) as hour,coalesce(count,0) as count from 
(
    SELECT extract (day from date) as day , extract (hour from date) as hr ,count(*) 
    FROM sr 
    where date>'2012-01-01' and date <'2012-01-07' 
    GROUP BY extract (day from date) , extract (hour from date) 
) AS cnt 
right outer join (SELECT * FROM generate_series ('2012-01-01'::timestamp, '2012-01-07 23:00', '1 hour') AS ts) as dtetable on extract (hour from ts) = cnt.hr and extract (day from ts) = cnt.day 
order by day,hour asc; 
0

Этот запрос предоставит вам то, что вы ищете,

select to_char(date_event, 'YYYY-MM-DD HH24:00') as time, count (to_char(date_event, 'HH24:00')) as count from views where date(date_event) > '2012-01-01' and date(date_event) > '2012-01-07' group by time order by time; 
+0

Спасибо Vinesh. Однако это не работает (временная метка при 0 не дается), а>> и < should be > = и <=. – SCO