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 :