PostgreSQL количество каждого статуса в день - PullRequest
1 голос
/ 21 января 2020

У меня есть следующая таблица:

Reservations
| id | status    | created_at          |
|  1 | Opened    | 2019-11-12 11:46:11 |
|  1 | Completed | 2019-11-19 23:03:24 |
|  1 | Pending   | 2019-11-15 12:04:13 |
|  2 | Opened    | 2019-11-14 11:46:11 |
|  2 | Completed | 2019-11-20 23:03:24 |
|  2 | Pending   | 2019-11-17 12:04:13 |

У меня также есть таблица с каждым календарным днем ​​с 2019-11-01 по 2019-12-31.

Мне нужно найти узнайте, сколько вхождений каждого статуса существует за календарный день за промежуток времени, указанный выше.

Если статус Открыт в 2019-12-14 и В ожидании в 2019-12-17, мне нужно сосчитать, что это было Открыто на каждый день с 2019-12-14 по 2019-12-17.

Идеально:

|2019-11-12 00:00:00 | Opened    | 1 |
|2019-11-12 00:00:00 | Pending   | 0 |
|2019-11-12 00:00:00 | Completed | 0 |
|2019-11-13 00:00:00 | Opened    | 1 |
|2019-11-13 00:00:00 | Pending   | 0 |
|2019-11-13 00:00:00 | Completed | 0 |
|2019-11-14 00:00:00 | Opened    | 2 |
|2019-11-14 00:00:00 | Pending   | 0 |
|2019-11-14 00:00:00 | Completed | 0 |
|2019-11-15 00:00:00 | Opened    | 1 |
|2019-11-15 00:00:00 | Pending   | 1 |
|2019-11-15 00:00:00 | Completed | 0 |

Любая помощь очень ценится.

Редактировать: The Решение от GMB ниже очень близко, но оно оставляет меня со следующей таблицей:

| status    | created_at          | ended_at            |
| Opened    | 2019-11-12 11:46:11 | 2019-11-15 12:04:13 |
| Pending   | 2019-11-15 12:04:13 | 2019-11-19 23:03:24 |
| Completed | 2019-11-19 23:03:24 |                     |
| Opened    | 2019-11-14 11:46:11 | 2019-11-17 12:04:13 |
| Pending   | 2019-11-17 12:04:13 | 2019-11-20 23:03:24 |
| Completed | 2019-11-20 23:03:24 |                     |

Как мне добавить дату окончания моего диапазона (2019-12-31) к отсутствующим значениям столбца?

Ответы [ 2 ]

0 голосов
/ 21 января 2020

Рассмотрим следующий запрос:

select 
    c.dt,
    s.status,
    count(t.status)
from 
    calendar c
    cross join (select distinct status from reservations) s
    left join (
        select 
            status, 
            created_at, 
            lead(created_at) over(partition by id order by created_at) ended_at
        from reservations
    ) t
        on  t.status = s.status
        and c.dt  + interval '1 day' >= t.created_at
        and c.dt + interval '1 day' < t.ended_at
group by c.dt, s.status
order by c.dt, s.status

Это работает путем перекрестного соединения таблицы календаря со списком различных состояний, доступных в таблице, и последующего соединения с подзапросом, использующим lead() для получить дату статуса next , связанного с каждой записью. Если у вас есть таблица статусов, вы можете использовать ее вместо подзапроса, который выбирает отдельные статусы.

Демонстрация на DB Fiddle :

dt                     | status    | count
:--------------------- | :-------- | ----:
2019-11-12 00:00:00+00 | Completed |     0
2019-11-12 00:00:00+00 | Opened    |     1
2019-11-12 00:00:00+00 | Pending   |     0
2019-11-13 00:00:00+00 | Completed |     0
2019-11-13 00:00:00+00 | Opened    |     1
2019-11-13 00:00:00+00 | Pending   |     0
2019-11-14 00:00:00+00 | Completed |     0
2019-11-14 00:00:00+00 | Opened    |     2
2019-11-14 00:00:00+00 | Pending   |     0
2019-11-15 00:00:00+00 | Completed |     0
2019-11-15 00:00:00+00 | Opened    |     1
2019-11-15 00:00:00+00 | Pending   |     1

Обратите внимание, что в скрипте БД показано, как использовать удобную Postgres функцию generate_series() для заполнения таблицы календаря.

0 голосов
/ 21 января 2020

Я бы сделал это следующим образом: получите начало и конец каждого статуса для каждого идентификатора, посчитайте количество повторений, используя вашу таблицу, с каждым календарным днем ​​с 2019-11-01 по 2019-12-31 и сделайте базовый подсчет c по статусу и дате

with Reservations cte as 
(
 select 
 a.id, a.status, a.created_at::date, 
 LAG(a.created_at::date, 1,0) OVER (PARTITION BY YEAR(a.id) ORDER BY YEAR(a.created_at)) 
 AS Ended_at
 Reservations a 
)
Select b.day, status, count(*)  
from Reservations a inner join calendar b on b.day >= created_at and
b.day < Ended_at       
group by b.day, status
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...