A gaps-and-islands problema mesmo.
Supondo:
- "Streaks" não são interrompidos por linhas de outros jogadores.
- Todas as colunas são definidas
NOT NULL. (Caso contrário, você precisa fazer mais.)
Isso deve ser mais simples e rápido, pois precisa apenas de dois
row_number() funções da janela
:SELECT DISTINCT ON (player_id)
player_id, count(*) AS seq_len, min(ts) AS time_began
FROM (
SELECT player_id, points, ts
, row_number() OVER (PARTITION BY player_id ORDER BY ts)
- row_number() OVER (PARTITION BY player_id, points ORDER BY ts) AS grp
FROM tbl
) sub
WHERE points = 100
GROUP BY player_id, grp -- omit "points" after WHERE points = 100
ORDER BY player_id, seq_len DESC, time_began DESC;
db<>fiddle aqui
Usando o nome da coluna
ts em vez de time , que é uma palavra reservada
em SQL padrão. É permitido no Postgres, mas com limitações e ainda é uma má ideia usá-lo como identificador. O "truque" é subtrair os números das linhas para que as linhas consecutivas caiam no mesmo grupo (
grp ) por (player_id, points) . Então filtre aqueles com 100 pontos, agregue por grupo e retorne apenas o resultado mais longo e mais recente por jogador.Explicação básica para a técnica:
Podemos usar
GROUP BY e DISTINCT ON no mesmo SELECT , GROUP BY é aplicado antes DISTINCT ON . Considere a sequência de eventos em um SELECT consulta:Sobre
DISTINCT ON :