Отслеживание статуса пользователя с использованием даты начала в PostgreSQL

#sql #postgresql #time-series #vertica

#sql #postgresql #временные ряды #vertica

Вопрос:

У меня есть набор данных, который включает идентификаторы пользователей, соответствующие им статусы (например, активированный, истекший и т.д.) и дату этого статуса («создан»).

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

Например, пользователь в 2019-01-01 18:30:00 имеет статус «АКТИВИРОВАН», затем в 2020-01-01 19:53:01 имеет статус «ИСТЕК», затем в 2020-02-01 снова имеет статус «АКТИВИРОВАН» до текущей даты.

Таким образом, я бы хотел, чтобы идентификатор пользователя и статус отображались между первой и второй датой как «АКТИВИРОВАННЫЙ», между второй и третьей датой как «ИСТЕКШИЙ», а с третьей даты до текущей даты как «АКТИВИРОВАННЫЙ».

Я довольно запутался в том, как это сделать, но из некоторых исследований в Интернете я получил / изменил этот фрагмент кода, который написан на Vertica. Однако он написан не на правильном диалекте и не включает статус так, как мне хотелось бы.

 SELECT id,
       status_dt,
       last_order_dt,
       CASE
           WHEN status_dt::date - last_order_dt::date < 30 then CASE
           WHEN nord = 1 then 'New'
           ELSE 'Active'
           END
           WHEN status_dt::date - last_order_dt::date < 90 then 'Active'
           WHEN status_dt::date - last_order_dt::date < 180 then 'Passive'
           ELSE 'Inactive'
       END AS status
FROM
  (SELECT id,
          last_order_dt,
          status_dt,
          conditional_true_event (first_order_dt is null
          OR last_order_dt > lag(last_order_dt)) OVER(partition BY id
          ORDER BY status_dt) AS nord
   FROM
     ( SELECT id,
              ts_first_value(created) AS first_order_dt,
              ts_last_value(created) AS last_order_dt,
              dt::date AS status_dt
      FROM
        (SELECT id,
                created
         FROM enabled
         UNION all SELECT distinct(id) AS id,
                          current_date   1 AS created
         FROM enabled ) z timeseries dt AS '1 day' OVER(partition BY id
         ORDER BY created) ) x ) y
WHERE status_dt <= current_date
ORDER BY 1,
         2 ;

with t AS
  ( SELECT id,
           [created],
           current_date,
           status
   FROM postgres_public.loc_application_status
   UNION all SELECT id,
                    dateadd(mm, 1, [created]),
                    current_date,
                    status
   FROM t
   WHERE dateadd(mm, 1, [created]) < coalesce(current_date, getdate()) )
SELECT id,
       [created],
       (CASE
            WHEN eomonth([created]) <= coalesce(current_date, cast(getdate() AS date)) then eomonth([created])
            ELSE coalesce(current_date, eomonth([created]))
        END) AS current_date,
       status
FROM t
ORDER BY id;
  

Комментарии:

1. Для начала, [created] должно быть created — квадратные скобки недопустимы в стандартном SQL. И dateadd(mm, 1, [created]), , вероятно, должно быть crated interval '1 month' . Не уверен, что getdate() делает, но coalesce(current_date, getdate()) выглядит довольно странно, поскольку current_date никогда не возвращается null . Я не знаю, что eomonth делает

2. Да, это было единственное, что я смог найти в Интернете. Я не уверен, действительно ли это полезно при написании кода, который выполняет описанную мной функцию

3. Пожалуйста, укажите пример ожидаемого результата с учетом вашего сценария. Вы говорите, что на человека должны быть ежедневные значения. Что происходит в день изменения статуса? В 2020-01-01 должен ли у пользователя A быть строка для ACTIVATED, EXPIRED или обоих?

4. Поскольку существует временная метка, может быть строка со временем, когда в последний момент пользователь имел статус «АКТИВИРОВАН», а следующая строка «ИСТЕКЛА», но это не обязательно, в зависимости от того, насколько это усложняет проблему. Главное, чего я хочу добиться, — это просто иметь возможность отслеживать статусы пользователей каждый день, чтобы также иметь возможность знать, например, сколько активных пользователей у меня в месяц.

5. Диалект запроса Vertica уже выглядит для меня немного сложным. Использование a TIMESERIES для отслеживания изменений статуса, а не диапазонов от даты до даты, является опасным действием и должно выполняться только тогда, когда это неизбежно — как бы мне ни нравилось TIMESERIES это предложение … Не могли бы вы добавить небольшую выборку вашей enabled таблицы, чтобы мы могли с ней поиграть?