Группировка по дате, с 0, когда count () не дает строк - PullRequest
2 голосов
/ 24 февраля 2012

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

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

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 записей), я пытаюсьпомнить о производительности.

Как этого добиться?

Спасибо!

Ответы [ 2 ]

7 голосов
/ 24 февраля 2012

Учитывая, что у вас нет дат в таблице, вам нужен способ их генерации. Вы можете использовать функцию 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 голосов
/ 24 февраля 2012

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

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;
...