PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come aggiungere un conteggio progressivo alle righe in una "serie" di giorni consecutivi

Basandosi su questa tabella (non utilizzando la parola chiave SQL "date" come nome della colonna.):

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

Domanda:

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;

Sottraendo una date da un'altra date restituisce un integer . Dato che stai cercando giorni consecutivi, ogni riga successiva sarebbe maggiore di uno . Se sottraiamo row_number() da ciò, l'intera serie finisce nello stesso gruppo (grp ) per pid . Quindi è semplice distribuire il numero per gruppo.

grp è calcolato con due sottrazioni, che dovrebbero essere più veloci. Un'alternativa altrettanto veloce potrebbe essere:

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

Una moltiplicazione, una sottrazione. La concatenazione e il casting di stringhe sono più costosi. Prova con EXPLAIN ANALYZE .

Non dimenticare di partizionare per pid inoltre in entrambi passaggi o mescolerai inavvertitamente i gruppi che dovrebbero essere separati.

Utilizzo di una sottoquery, poiché in genere è più veloce di un CTE . Non c'è niente qui che una semplice sottoquery non possa fare.

E poiché l'hai menzionato:dense_rank() ovviamente non necessario qui. row_number() di base fa il suo lavoro.