En gaps-and-islands problem verkligen.
Förutsatt:
- "Streaks" avbryts inte av rader från andra spelare.
- Alla kolumner är definierade
NOT NULL
. (Annars måste du göra mer.)
Detta bör vara enklast och snabbast eftersom det bara behöver två snabba row_number()
fönsterfunktioner
:
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<>fiol här
Använder kolumnnamnet ts
istället för time
, som är ett reserverat ord
i standard SQL. Det är tillåtet i Postgres, men med begränsningar och det är fortfarande en dålig idé att använda det som identifierare.
"Knepet" är att subtrahera radnummer så att på varandra följande rader faller i samma grupp (grp
) per (player_id, points)
. Då filtrera de med 100 poäng, samla per grupp och returnera endast det längsta, senaste resultatet per spelare.
Grundläggande förklaring till tekniken:
Vi kan använda GROUP BY
och DISTINCT ON
i samma SELECT
, GROUP BY
tillämpas före DISTINCT ON
. Tänk på händelseförloppet i en SELECT
fråga:
Om DISTINCT ON
: