Ein Lücken-und-Inseln in der Tat ein Problem.
Annahme:
- "Streaks" werden nicht durch Reihen anderer Spieler unterbrochen.
- Alle Spalten sind
NOT NULL
definiert . (Andernfalls müssen Sie mehr tun.)
Dies sollte am einfachsten und schnellsten sein, da es nur zwei schnelle row_number()
Fensterfunktionen
:
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
Verwenden Sie den Spaltennamen ts
statt time
, das ein reserviertes Wort
ist in Standard-SQL. Es ist in Postgres erlaubt, aber mit Einschränkungen, und es ist immer noch eine schlechte Idee, es als Bezeichner zu verwenden.
Der „Trick“ besteht darin, Zeilennummern zu subtrahieren, sodass aufeinanderfolgende Zeilen in dieselbe Gruppe fallen (grp
) pro (player_id, points)
. Dann Filtere die mit 100 Punkten, sammle pro Gruppe und gib nur das längste, neueste Ergebnis pro Spieler zurück.
Grundlegende Erklärung für die Technik:
Wir können GROUP BY
verwenden und DISTINCT ON
im gleichen SELECT
, GROUP BY
wird vorher angewendet DISTINCT ON
. Betrachten Sie die Abfolge von Ereignissen in einem SELECT
Abfrage:
Über DISTINCT ON
: