A brechas-e-islas problema de hecho.
Suponiendo:
- Las "rachas" no se ven interrumpidas por filas de otros jugadores.
- Todas las columnas están definidas
NOT NULL
. (Si no, tienes que hacer más.)
Esto debería ser más simple y rápido, ya que solo necesita dos rápidos row_number()
funciones de ventana
:
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 aquí
Usando el nombre de columna ts
en lugar de time
, que es una palabra reservada
en SQL estándar. Está permitido en Postgres, pero con limitaciones y sigue siendo una mala idea usarlo como identificador.
El "truco" es restar números de fila para que las filas consecutivas caigan en el mismo grupo (grp
) por (player_id, points)
. Entonces filtre los que tengan 100 puntos, agregue por grupo y devuelva solo el resultado más largo y más reciente por jugador.
Explicación básica de la técnica:
Podemos usar GROUP BY
y DISTINCT ON
en el mismo SELECT
, GROUP BY
se aplica antes DISTINCT ON
. Considere la secuencia de eventos en un SELECT
consulta:
Acerca de DISTINCT ON
: