PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Komplexe „Lücken und Inseln“-Ausgabe

Es ist unklar, wie Sie den type bestimmen für jede Periode. Ich habe die Mindestanzahl gewählt.

Angenommen diese grundlegende Tabellendefinition:

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

Grundsätzlich empfehle ich Fensterfunktionen in zwei verschachtelten Unterabfragen, um Mitglieder derselben Periode (Insel) zu identifizieren. Dann aggregieren:

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;

Ergebnis (basierend auf Ihren Beispieldaten):

  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

Wenn derselbe Tag für dieselbe Person mehrfach mit unterschiedlichen Typen erfasst werden kann und Sie nur eindeutig zählen möchten Tage, mache daraus:count(DISTINCT eventdate) AS days .

Verwandte, mit ausführlicher Erklärung:

Übrigens, eventdate - 6 funktioniert für den Datentyp date , aber nicht für timestamp :