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
: