Redshift - оконная функция значений за последний час - PullRequest
2 голосов
/ 23 января 2020

У меня есть таблица со столбцами, похожими на: event_id, store_id, event_datetime.

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

SELECT 
    event_id, 
    COUNT(event_id) OVER (PARTITION BY store_id ORDER BY event_datetime 
                          ROWS BETWEEN 5 preceding and current row)
FROM mtable;

, чтобы получить 5 предыдущих событий в магазине, но мне нужно, чтобы это число было переменным к общему количеству событий за последний час. Есть какой-либо способ сделать это? В противном случае мне нужно соединить таблицу с самим собой, например:

SELECT 
    event_id, 
    COUNT(prevevents.event_id) 
FROM mtable m 
INNER JOIN mtable prevevents 
    ON prevevents.event_datetime BETWEEN (m.event_datetime - interval '1 hour') AND
       m.event_datetime

Этот запрос выполняется вечно, так как это перекрестное соединение и приводит к декартовому произведению между таблицами. Любые предложения о том, как этого добиться? В таблице несколько миллионов событий, поэтому любые улучшения будут очень полезны!

Ответы [ 2 ]

1 голос
/ 23 января 2020

Если я правильно понимаю, мы могли бы решить эту проблему в два этапа. Сначала вычислите количество в каждом магазине за каждый час, используя TO_CHAR, чтобы определить дату часа. Затем выполните подзапрос и возьмите задержку этого количества, чтобы сгенерировать счет за предыдущий час.

WITH cte AS (
    SELECT *,
        TO_CHAR(event_datetime, 'YYYY-MM-DD HH24') AS event_hour,
        COUNT(event_id) OVER (PARTITION BY store_id,
                  TO_CHAR(event_datetime, 'YYYY-MM-DD HH24')) event_cnt
    FROM mtable
)

SELECT
   event_id,
   LAG(event_cnt) OVER (PARTITION BY store_id ORDER BY event_hour) prev_event_cnt
FROM cte;
1 голос
/ 23 января 2020

Я не уверен, поддерживает ли Redshift условие окна range . Если это так, это должно быть так просто:

SELECT 
    event_id, 
    COUNT(event_id) OVER (
        PARTITION BY store_id 
        ORDER BY DATE_PART(epoch, date_column)
        RANGE BETWEEN 3600 PRECEDING AND 1 PRECEDING
    ) cnt
FROM mtable;

Если эта функция недоступна, то я не вижу другой вариант, что соединение или коррелированный подзапрос:

select 
    t.event_id,
    (
        select count(*) 
        from mytable t1 
        where 
            t1.store_id = t.store_id 
            and t1.event_datetime >= t.event_datetime - interval '1 hour'
            and t1.event_datetime < t.event_datetime
    ) cnt
from mytable t

Коррелированный подзапрос может работать лучше, поскольку он предварительно агрегирует данные. Для соединения или подзапроса убедитесь, что у вас есть индекс для (store_id, event_datetime).

...