Na základě této tabulky (bez použití klíčového slova SQL "date" jako název sloupce.):
CREATE TABLE tbl(
pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);
Dotaz:
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;
Odečtením date
z jiného date
dává integer
. Protože hledáte po sobě jdoucí dny, každý další řádek bude o jednu větší . Pokud odečteme row_number()
z toho celý pruh skončí ve stejné skupině (grp
) za pid
. Pak je snadné rozdělit počet na skupinu.
grp
se počítá se dvěma odečítáními, které by měly být nejrychlejší. Stejně rychlá alternativa by mohla být:
the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp
Jedno násobení, jedno odčítání. Zřetězení a odlévání strun je dražší. Otestujte pomocí EXPLAIN ANALYZE
.
Nezapomeňte rozdělit podle pid
navíc v obě kroky, nebo neúmyslně smícháte skupiny, které by měly být odděleny.
Pomocí poddotazu, protože ten je obvykle rychlejší než CTE . Není zde nic, co by prostý poddotaz nedokázal.
A protože jste to zmínil:dense_rank()
zjevně není zde nutné. Základní row_number()
dělá svou práci.