Как я могу заполнить значения в postgres

#postgresql #datetime #window-functions

#postgresql #дата и время #оконные функции

Вопрос:

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

Фактический результат: Мой код в настоящее время продолжает заполнять статус даже после закрытия проблемы.

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

 WITH cte (cal_month) as  (  SELECT date_trunc('month', timestamp '2021-07-01T00:00:00')  UNION ALL   SELECT date_trunc('month', timestamp '2021-08-01T00:00:00')  UNION ALL   SELECT date_trunc('month', timestamp '2021-09-01T00:00:00')  UNION ALL   SELECT date_trunc('month', timestamp '2021-10-01T00:00:00')  UNION ALL   SELECT date_trunc('month', timestamp '2021-11-01T00:00:00')  UNION ALL   SELECT date_trunc('month', timestamp '2021-12-01T00:00:00') ), cte_2 (cal_month, issue_id, version, action_day, action_month, issue_status) as  ( SELECT m.cal_month  , issue_id  , version   , date_trunc('day', action_timestamp) as action_day   , date_trunc('month', action_timestamp) as action_month  , issue_status   , SUM(CASE WHEN issue_status IS NOT NULL THEN 1 END) OVER (ORDER BY cal_month, issue_status, version) as grp FROM cte m LEFT JOIN issue_history h  ON m.cal_month = date_trunc('month', action_timestamp)  AND issue_id IN (23865) ORDER BY cal_month, issue_id, version ) SELECT *  , first_value(issue_status) over (partition by grp) as derived_issue_status FROM cte_2 ORDER BY cal_month, issue_id, version  

Пример вывода из кода

месяц идентификатор проблемы версия день действия месяц действия состояние проблемы врп derived_issue_статус
2021-07-01T00:00:00 23865 1 2021-07-25T00:00:00 2021-07-01T00:00:00 Для Разрешения 1 Для Разрешения
2021-07-01T00:00:00 23865 2 2021-07-25T00:00:00 2021-07-01T00:00:00 Для Разрешения 2 Для Разрешения
2021-07-01T00:00:00 23865 3 2021-07-26T00:00:00 2021-07-01T00:00:00 Для Разрешения 3 Для Разрешения
2021-07-01T00:00:00 23865 4 2021-07-26T00:00:00 2021-07-01T00:00:00 Для Разрешения 4 Для Разрешения
2021-08-01T00:00:00 нулевой нулевой нулевой нулевой нулевой 4 Для Разрешения
2021-09-01T00:00:00 нулевой нулевой нулевой нулевой нулевой 4 For Resolution
2021-10-01T00:00:00 нулевой нулевой нулевой нулевой нулевой 4 For Resolution
2021-11-01T00:00:00 23865 5 2021-11-09T00:00:00 2021-11-01T00:00:00 Для Разрешения 5 For Resolution
2021-11-01T00:00:00 23865 6 2021-11-09T00:00:00 2021-11-01T00:00:00 Для Разрешения 6 For Resolution
2021-11-01T00:00:00 23865 7 2021-11-09T00:00:00 2021-11-01T00:00:00 Для Разрешения 7 For Resolution
2021-11-01T00:00:00 23865 8 2021-11-15T00:00:00 2021-11-01T00:00:00 Закрытый 8 Closed
2021-12-01T00:00:00 нулевой нулевой нулевой нулевой нулевой 8 Closed

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

1. В качестве примечания: ваш cal_month может быть упрощен до SELECT * from generate_series(date '2021-07-01', date '2021-12-01', interval ' 1 month')

2. если вы добавите в cte_2 предложение WHERE с status != 'Closed' the record for december should not exist. BTW: On 2021-08-01`, будет ли замечен идентификатор null проблемы, действительно ли это то, что вы хотите ?

Ответ №1:

Попробуйте это :

 WITH cte_2 AS  ( SELECT m.cal_month  , issue_id  , version   , date_trunc('day', action_timestamp) as action_day   , date_trunc('month', action_timestamp) as action_month  , issue_status   , count(*) FILTER (WHERE issue_status IS NOT NULL) OVER (ORDER BY cal_month, issue_status, version) as grp  , (jsonb_agg(to_jsonb(issue_status)) FILTER (WHERE issue_status IS NOT NULL) OVER (ORDER BY cal_month, issue_status, version))-gt;'-1' as derived_issue_status  FROM generate_series(date '2021-07-01', date '2021-12-01', interval ' 1 month') m  LEFT JOIN issue_history h  ON m.cal_month = date_trunc('month', action_timestamp)  AND issue_id IN (23865)  ORDER BY cal_month, issue_id, version ) SELECT m.cal_month  , issue_id  , version  , action_day   , action_month  , issue_status   , grp  , CASE  WHEN derived_issue_status = 'Closed' AND issue_status IS NULL  THEN NULL  ELSE derived_issue_status  END AS derived_issue_status FROM cte_2 ORDER BY cal_month, issue_id, version  

Предложения об изменениях :

(1) Как предложено @a_horse_with_no_name, cte подавляется и заменяется generate_series(date '2021-07-01', date '2021-12-01', interval ' 1 month') в cte2

(2) В cte2 :

 SUM(CASE WHEN issue_status IS NOT NULL THEN 1 END) OVER (ORDER BY cal_month, issue_status, version) as grp  

заменено на

 count(*) FILTER (WHERE issue_status IS NOT NULL) OVER (ORDER BY cal_month, issue_status, version) as grp  

даже если grp in больше не используется в окончательном запросе, потому derived_issue_status что вычисляется в cte2 с помощью оператора new :

 (jsonb_agg(to_jsonb(issue_status)) FILTER (WHERE issue_status IS NOT NULL) OVER (ORDER BY cal_month, issue_status, version))-gt;gt;'-1' as derived_issue_status  

(3) A CASE добавляется в окончательный запрос для отображения derived_issue_status = NULL, когда текущее значение issue_status равно NULL, а последнее ненулевое значение issue_status = «Закрыто».

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

1. Спасибо за это! Это почти на месте. Я хочу иметь только календарные месяцы для каждого месяца, когда проблема открыта, даже если для нее нет события. Мне нужно сгенерировать серию дат на следующие 12 месяцев, поэтому после закрытия проблемы будет создано много пустых строк. Есть ли способ обойти это?

2. Я подошел к этому так. cte 1 создайте раздел для каждого набора событий открытия и закрытия для каждой проблемы, используя ФИЛЬТР COUNT (*) (ГДЕ issue_status = 1) (РАЗДЕЛ ПО ПОРЯДКУ идентификаторов выпуска ПО версии) в качестве grp. В приведенном выше примере все эти события были бы в grp 1. Если бы проблема была вновь открыта, были бы grp 1 и 2. cte 2 извлекает самое раннее открытие и последнее закрытие в рамках grp. Эти значения передаются в generate_series для каждой проблемы. Присоедините cte2 к предложенному вами cte и удалите оператор case, который проверяет наличие нулевого и закрытого статуса.?