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

Złożona kwestia „Gaps and Islands”

Nie jest jasne, w jaki sposób określasz type dla każdego okresu. Wybrałem minimalną liczbę.

Zakładając tę ​​podstawową definicję tabeli:

CREATE TABLE tbl (person text, eventdate date, type int);

Zasadniczo sugeruję funkcje okien w dwóch zagnieżdżonych podzapytaniach w celu zidentyfikowania członków tego samego okresu (wyspy). Następnie agregacja:

SELECT person, period
     , min(eventdate) AS startdate
     , max(eventdate) AS enddate
     , count(*)       AS days
     , min(type)      AS type
FROM  (
   SELECT person, eventdate, type
        , count(gap) OVER (PARTITION BY person ORDER BY eventdate) AS period
   FROM  (
      SELECT person, eventdate, type
           , CASE WHEN lag(eventdate) OVER (PARTITION BY person ORDER BY eventdate)
                     > eventdate - 6  -- within 5 days
                  THEN NULL           -- same period
                  ELSE TRUE           -- next period
             END AS gap
      FROM   tbl
      ) sub
   ) sub
GROUP  BY person, period
ORDER  BY person, period;

Wynik (na podstawie przykładowych danych):

  person  | period | startdate  |  enddate   | days | type
----------+--------+------------+------------+------+------
 <uuid-1> |      1 | 2016-05-14 | 2016-05-22 |    5 |  300
 <uuid-1> |      2 | 2016-05-30 | 2016-06-01 |    2 |  300
 <uuid-1> |      3 | 2016-06-21 | 2016-06-21 |    1 |  300
 <uuid-2> |      1 | 2016-05-22 | 2016-05-27 |    2 |  301
 <uuid-2> |      2 | 2016-06-15 | 2016-06-23 |    4 |  300
 <uuid-2> |      3 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-3> |      1 | 2016-05-14 | 2016-05-14 |    1 |  300
 <uuid-3> |      2 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-4> |      1 | 2016-06-16 | 2016-06-16 |    1 |  300
 <uuid-4> |      2 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-5> |      1 | 2016-06-20 | 2016-06-20 |    1 |  300

Jeśli ten sam dzień dla tej samej osoby można wprowadzić wiele razy z różnymi typami, a chcesz liczyć tylko różne dni, zrób to:count(DISTINCT eventdate) AS days .

Powiązane, ze szczegółowym wyjaśnieniem:

BTW, eventdate - 6 działa dla danych typu date , ale nie dla timestamp :




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak utworzyć indeks na LOWER(users.username) w Railsach (za pomocą postgresa)

  2. Utwórz diagram ER w pgAdmin

  3. TypeORM warunkowy dopuszczający wartość null?

  4. Jak przesłać dane z AWS Postgres RDS do S3 (wtedy Redshift)?

  5. Jak czytać z 32-bitowego .mdb z 64-bitowym sterownikiem Pythona i odbc?