Статистический режим с postgres - PullRequest
0 голосов
/ 03 февраля 2012

У меня есть таблица с такой схемой:

create table mytable (creation_date timestamp,
                      value int,
                      category int);

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

select category,foo.h as h,value, count(value) from mytable, (
      select date_trunc('hour', 
                        '2000-01-01 00:00:00'::timestamp+generate_series(0,23)*'1 hour'::interval)::time as h) AS foo 
      where date_part('hour',creation_date) = date_part('hour',foo.h) and
            date_part('dow',creation_date) > 0 and date_part('dow',creation_date) < 6
      group by category,h,value;

В результате я получил что-то вроде этого:

category |    h     |  value  | count 
---------+----------+---------+-------
       1 | 00:00:00 |       2 |     1
       1 | 01:00:00 |       2 |     1
       1 | 02:00:00 |       2 |     6
       1 | 03:00:00 |       2 |    31
       1 | 03:00:00 |       3 |    11
       1 | 04:00:00 |       2 |    21
       1 | 04:00:00 |       3 |     9
       1 | 13:00:00 |       1 |    14
       1 | 14:00:00 |       1 |    10
       1 | 14:00:00 |       2 |     7
       1 | 15:00:00 |       1 |    52

например, в 04:00 у меня есть значения 2 и 3, со счетчиками 21 и 9 соответственно, мне нужно только значение с наибольшим количеством, которое было бы в статическом режиме.

Кстати, у меня более 2M записей

Ответы [ 2 ]

2 голосов
/ 04 февраля 2012

Это может быть проще:

SELECT DISTINCT ON (category, extract(hour FROM creation_date)::int)
       category
     , extract(hour FROM creation_date)::int AS h
     , count(*)::int AS max_ct
     , value
FROM   mytable
WHERE  extract(isodow FROM creation_date) < 6 -- no sat or sun
GROUP  BY 1,2,4
ORDER  BY 1,2,3 DESC;

В основном это шаги:

  1. Исключая выходные (WHERE ...). Используйте ISODOW для упрощения выражения.
  2. Извлечение hour из timestamp как h.
  3. Группировка по category, h и value.
  4. Подсчитать количество строк в комбинации из трех; приведение к integer - нам не нужно bigint.
  5. Заказ по category, h и наибольшему количеству (DESC).
  6. Выберите только первый ряд (наибольшее количество) для (category, h) с соответствующим category.

Я могу сделать это на одном уровне запроса, потому что DISTINCT применяется после агрегатной функции.

Результат будет содержать нет строк для любых (category, h) без записей вообще. Если вам нужно заполнить пробелы, LEFT JOIN на это:

SELECT c.category, h.h
FROM   cat_tbl c
CROSS  JOIN (SELECT generate_series(0, 23) AS h) h
1 голос
/ 04 февраля 2012

Учитывая размер вашей таблицы, у меня возникнет соблазн использовать ваш запрос для построения временной таблицы, а затем выполнить запрос для этого, чтобы завершить результаты.

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

select
    category, h, value, count
from
    summary_table s1
where
    not exists 
    (select * from summary_table s2
        where s1.category = s2.category and
                  s1.h = s2.h and
                   (s1.count < s2.count 
            OR (s1.count = s2.count and s1.value > s2.value));

Если вы не хотите создавать таблицу, вы можете использовать предложение WITH, чтобы присоединить к нему свой запрос.

with summary_table as (
select category,foo.h as h,value, count(value) as count from mytable, (
      select date_trunc('hour', 
                        '2000-01-01 00:00:00'::timestamp+generate_series(0,23)*'1 hour'::interval)::time as h) AS foo 
      where date_part('hour',creation_date) = date_part('hour',foo.h) and
            date_part('dow',creation_date) > 0 and date_part('dow',creation_date) < 6
      group by category,h,value)
select
    category, h, value, count
from
    summary_table s1
where
    not exists 
    (select * from summary_table s2
        where s1.category = s1.category and
                  s1.h = s2.h and
                   (s1.count < s2.count 
            OR (s1.count = s2.count and s1.value > s2.value));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...