luki-i-wyspy rzeczywiście problem.
Zakładając:
- „Serie” nie są przerywane rzędami innych graczy.
- Wszystkie kolumny są zdefiniowane
NOT NULL. (W przeciwnym razie musisz zrobić więcej.)
Powinno to być najprostsze i najszybsze, ponieważ wymaga tylko dwóch szybkich row_number() funkcje okien
:
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 tutaj
Używanie nazwy kolumny ts zamiast time , czyli słowo zastrzeżone
w standardowym SQL. Jest to dozwolone w Postgresie, ale z ograniczeniami i nadal złym pomysłem jest używanie go jako identyfikatora.
"Sztuczka" polega na odjęciu numerów wierszy tak, aby kolejne wiersze należały do tej samej grupy (grp ) za (player_id, points) . Wtedy filtruj te z 100 punktami, agreguj według grupy i zwracaj tylko najdłuższy, najnowszy wynik na gracza.
Podstawowe wyjaśnienie techniki:
Możemy użyć GROUP BY i DISTINCT ON w tym samym SELECT , GROUP BY jest stosowany przed DISTINCT ON . Rozważ sekwencję zdarzeń w SELECT zapytanie:
Informacje o DISTINCT ON :