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

So fügen Sie Zeilen in einer Reihe aufeinanderfolgender Tage eine laufende Zählung hinzu

Aufbauend auf dieser Tabelle (ohne das SQL-Schlüsselwort "date" als Spaltenname.):

CREATE TABLE tbl(
  pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);

Abfrage:

SELECT pid, the_date
     , row_number() OVER (PARTITION BY pid, grp ORDER BY the_date) AS in_streak
FROM  (
   SELECT *
        , the_date - '2000-01-01'::date
        - row_number() OVER (PARTITION BY pid ORDER BY the_date) AS grp
   FROM   tbl
) sub
ORDER  BY pid, the_date;

Subtrahieren eines date von einem anderen date ergibt eine integer . Da Sie nach aufeinanderfolgenden Tagen suchen, wäre jede nächste Zeile um eins größer . Wenn wir row_number() subtrahieren Dadurch landet der gesamte Streak in derselben Gruppe (grp ) per pid . Dann ist es einfach, die Anzahl pro Gruppe zu verteilen.

grp wird mit zwei Subtraktionen berechnet, was am schnellsten sein sollte. Eine ebenso schnelle Alternative könnte sein:

the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp

Eine Multiplikation, eine Subtraktion. Das Verketten und Casting von Zeichenfolgen ist teurer. Testen Sie mit EXPLAIN ANALYZE .

Vergessen Sie nicht, nach pid zu partitionieren zusätzlich in beiden oder Sie vermischen versehentlich Gruppen, die getrennt werden sollten.

Verwenden einer Unterabfrage, da diese normalerweise schneller ist als ein CTE . Hier gibt es nichts, was eine einfache Unterabfrage nicht tun könnte.

Und da du es schon erwähnt hast:dense_rank() ist offensichtlich nicht hier notwendig. Grundlegende row_number() macht den Job.