PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment ajouter un décompte courant aux lignes dans une "série" de jours consécutifs

S'appuyer sur cette table (sans utiliser le mot-clé SQL "date" comme nom de colonne.):

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

Requête :

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;

Soustraire une date d'une autre date donne un integer . Étant donné que vous recherchez des jours consécutifs, chaque ligne suivante serait supérieure de un . Si nous soustrayons row_number() à partir de là, toute la série se retrouve dans le même groupe (grp ) par pid . Ensuite, il est simple de distribuer le nombre par groupe.

grp est calculé avec deux soustractions, ce qui devrait être le plus rapide. Une alternative tout aussi rapide pourrait être :

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

Une multiplication, une soustraction. La concaténation et le casting de chaînes coûtent plus cher. Testez avec EXPLAIN ANALYZE .

N'oubliez pas de partitionner par pid en plus dans les deux étapes, ou vous mélangerez par inadvertance des groupes qui devraient être séparés.

Utiliser une sous-requête, car cela est généralement plus rapide qu'un CTE . Il n'y a rien ici qu'une simple sous-requête ne puisse pas faire.

Et puisque vous l'avez mentionné :dense_rank() n'est évidemment pas nécessaire ici. Basique row_number() fait le travail.