Как мне запросить Postgres для подсчета разных дат из определенного временного ряда? - PullRequest
0 голосов
/ 22 мая 2018

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

time                   | user_id
--------------------------------
2018-05-01 00:00:00+02 | 56
2018-05-01 00:00:00+02 | 64
2018-05-01 00:00:00+02 | 56
2018-05-02 00:00:00+02 | 27
2018-05-02 00:00:00+02 | 64
...

Я хочу запросить в базе данных Postgres количество активных пользователей на дату.Пользователь активен, если у него есть посещения в 10 отдельных дат за предыдущие 30 дней.Например, для количества на дату 2018-05-22 запрос будет:

select count(*) from (
    select
        user_id,
        count(distinct time::date) as cnt
    from visit
    where
        time::date > '2018-05-22'::date - interval '30 days'
    group by user_id
    having count(distinct time::date) >= 10
    order by cnt desc
) t

Результатом будет одно число.Это работает правильно.Что я должен изменить в этом запросе, чтобы получить количества для каждой даты из определенного временного ряда?Требуемый результат должен быть таким:

date       | quantity
---------------------
2018-05-01 | 38
2018-05-02 | 26
2018-05-03 | 35
2018-05-04 | 44
...

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Самый простой метод использует generate_series():

select g.dte, count(*)
from (select g.dte, v.user_id, count(distinct v.time::date) as cnt
      from generate_series('2018-05-01'::date, '2018-05-22'::date, interval '1 day') g(dte) left join
           visit v
           on v.time::date <= g.dte and
              v.time::date > '2018-05-22'::date - interval '30 days'
      group by g.dte, v.user_id
      having count(distinct v.time::date) >= 10
     ) vd
group by g.dte
order by g.dte;

Если у вас большой объем данных, могут быть более быстрые способы.Если это проблема, задайте другой вопрос.

0 голосов
/ 22 мая 2018

Сначала создайте таблицу календаря, полную всех дат, которые вам когда-либо понадобятся.

Скажем, от '1900-01-01' до '2099-12-31'?

Тогда это в основном JOIN ...

SELECT
    calendar_date, count(*)
FROM
(
    SELECT
        CALENDAR_TABLE.calendar_date,
        visit.user_id,
        COUNT(DISTINCT visit.time::date) as cnt
    FROM
        CALENDAR_TABLE
    INNER JOIN
        visit
            ON  visit.time >= CALENDAR_TABLE.calendar_date - interval '30 days'
            AND visit.time <  CALENDAR_TABLE.calendar_date + interval '01 days'
    WHERE
        CALENDAR_TABLE.calendar_date BETWEEN '2018-05-01' AND '2018-05-22'
    GROUP BY
        CALENDAR_TABLE.calendar_date,
        visit.user_id
    HAVING
        COUNT(DISTINCT visit.time::date) >= 10
) t
GROUP BY
    calendar_date

Или, возможно ...

SELECT
    calendar_date, count(*)
FROM
(
    SELECT
        CALENDAR_TABLE.calendar_date,
        visit.user_id,
        COUNT(*) as cnt
    FROM
        CALENDAR_TABLE
    INNER JOIN
    (
        SELECT
           user_id,
           time::date   AS user_date
        FROM
           visit
        GROUP BY
           user_id,
           time::date
    )
        visit
            ON  visit.user_date >= CALENDAR_TABLE.calendar_date - interval '30 days'
            AND visit.user_date <  CALENDAR_TABLE.calendar_date + interval '01 days'
    WHERE
        CALENDAR_TABLE.calendar_date BETWEEN '2018-05-01' AND '2018-05-22'
    GROUP BY
        CALENDAR_TABLE.calendar_date,
        visit.user_id
    HAVING
        COUNT(*) >= 10
) t
GROUP BY
    calendar_date

Это может снизить объем памяти, но может замедлить объединение и фильтрацию ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...