A gaps-and-islands probleem inderdaad.
Ervan uitgaande:
- "Streaks" worden niet onderbroken door rijen van andere spelers.
- Alle kolommen zijn gedefinieerd
NOT NULL
. (Anders moet je meer doen.)
Dit zou het eenvoudigst en snelst moeten zijn, omdat er maar twee snelle row_number()
vensterfuncties
:
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 hier
De kolomnaam ts
gebruiken in plaats van time
, wat een gereserveerd woord
is in standaard SQL. Het is toegestaan in Postgres, maar met beperkingen en het is nog steeds een slecht idee om het als identifier te gebruiken.
De "truc" is om rijnummers af te trekken zodat opeenvolgende rijen in dezelfde groep vallen (grp
) per (player_id, points)
. Dan filter die met 100 punten, aggregeer per groep en retourneer alleen het langste, meest recente resultaat per speler.
Basisverklaring voor de techniek:
We kunnen GROUP BY
. gebruiken en DISTINCT ON
in dezelfde SELECT
, GROUP BY
wordt voor toegepast DISTINCT ON
. Overweeg de volgorde van gebeurtenissen in een SELECT
vraag:
Over DISTINCT ON
: