PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Generuj szeregi czasowe z dziennymi statystykami za pomocą zapytania PostgreSQL

Krok 1. Oblicz skumulowaną sumę stanu dla każdego zamówienia, używając wartości NOWY =1, AKTYWNY =1, WYKONANY =2:

select 
    order_id, timestamp::date as day, 
    sum(case new_state when 'DONE' then 2 else 1 end) over w as state
from order_state_history h
join orders o on o.id = h.order_id
where o.type = 1
window w as (partition by order_id order by timestamp)

 order_id |    day     | state 
----------+------------+-------
    10000 | 2001-01-01 |     1
    10000 | 2001-01-02 |     2
    10000 | 2001-01-03 |     4
    10001 | 2001-01-02 |     1
    10004 | 2001-01-05 |     1
    10004 | 2001-01-10 |     3
(6 rows)

Krok 2. Oblicz macierz przejścia dla każdego zamówienia na podstawie stanów z kroku 1 (2 oznacza NOWY->AKTYWNY, 3 oznacza NOWY->GOTOWY, 4 oznacza AKTYWNY->GOTOWY):

select 
    order_id, day, state,
    case when state = 1 then 1 when state = 2 or state = 3 then -1 else 0 end as new,
    case when state = 2 then 1 when state = 4 then -1 else 0 end as active,
    case when state > 2 then 1 else 0 end as done
from (
    select 
        order_id, timestamp::date as day, 
        sum(case new_state when 'DONE' then 2 else 1 end) over w as state
    from order_state_history h
    join orders o on o.id = h.order_id
    where o.type = 1
    window w as (partition by order_id order by timestamp)
    ) s

 order_id |    day     | state | new | active | done 
----------+------------+-------+-----+--------+------
    10000 | 2001-01-01 |     1 |   1 |      0 |    0
    10000 | 2001-01-02 |     2 |  -1 |      1 |    0
    10000 | 2001-01-03 |     4 |   0 |     -1 |    1
    10001 | 2001-01-02 |     1 |   1 |      0 |    0
    10004 | 2001-01-05 |     1 |   1 |      0 |    0
    10004 | 2001-01-10 |     3 |  -1 |      0 |    1
(6 rows)

Krok 3. Oblicz skumulowaną sumę każdego stanu dla serii dni:

select distinct
    day::date,
    sum(new) over w as new,
    sum(active) over w as active,
    sum(done) over w as done
from generate_series('2001-01-01'::date, '2001-01-10', '1d'::interval) day
left join (
    select 
        order_id, day, state,
        case when state = 1 then 1 when state = 2 or state = 3 then -1 else 0 end as new,
        case when state = 2 then 1 when state = 4 then -1 else 0 end as active,
        case when state > 2 then 1 else 0 end as done
    from (
        select 
            order_id, timestamp::date as day, 
            sum(case new_state when 'DONE' then 2 else 1 end) over w as state
        from order_state_history h
        join orders o on o.id = h.order_id
        where o.type = 1
        window w as (partition by order_id order by timestamp)
        ) s
    ) s
using(day)
window w as (order by day)
order by 1

    day     | new | active | done 
------------+-----+--------+------
 2001-01-01 |   1 |      0 |    0
 2001-01-02 |   1 |      1 |    0
 2001-01-03 |   1 |      0 |    1
 2001-01-04 |   1 |      0 |    1
 2001-01-05 |   2 |      0 |    1
 2001-01-06 |   2 |      0 |    1
 2001-01-07 |   2 |      0 |    1
 2001-01-08 |   2 |      0 |    1
 2001-01-09 |   2 |      0 |    1
 2001-01-10 |   1 |      0 |    2
(10 rows)   



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sprawdź, czy w tablicy Postgres istnieje NULL

  2. Jak mogę połączyć 3 stoły i obliczyć poprawną sumę pól z 2 stołów bez zduplikowanych wierszy?

  3. Postgresql SELECT, jeśli ciąg zawiera

  4. Sprawdź całą tabelę pod kątem pojedynczej wartości

  5. Zadania rake wydają się ignorować konfigurację database.yml