PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como adicionar uma contagem em execução às linhas em uma 'sequência' de dias consecutivos


Com base nesta tabela (sem usar a palavra-chave SQL "date" como nome da coluna.):
CREATE TABLE tbl(
  pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);

Consulta:
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;

Subtraindo uma date de outra date produz um integer . Como você está procurando dias consecutivos, cada linha seguinte seria maior em um . Se subtrairmos row_number() a partir disso, toda a sequência acaba no mesmo grupo (grp ) por pid . Então é simples distribuir o número por grupo.

grp é calculado com duas subtrações, que devem ser mais rápidas. Uma alternativa igualmente rápida poderia ser:
the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp

Uma multiplicação, uma subtração. A concatenação e a conversão de strings são mais caras. Teste com EXPLAIN ANALYZE .

Não se esqueça de particionar por pid adicionalmente em ambos passos, ou você vai misturar inadvertidamente grupos que deveriam ser separados.

Usando uma subconsulta, pois geralmente é mais rápida que uma CTE . Não há nada aqui que uma subconsulta simples não possa fazer.

E já que você mencionou:dense_rank() obviamente não necessário aqui. Básico row_number() faz o trabalho.