A gaps-and-islands проблем наистина.
Приемайки:
- „Поредиците“ не се прекъсват от редове от други играчи.
- Всички колони са дефинирани
NOT NULL
. (В противен случай трябва да направите повече.)
Това трябва да е най-простото и бързо, тъй като се нуждае само от два бързи row_number()
функции на прозорец
:
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 тук
Използване на името на колоната ts
вместо time
, което е запазена дума
в стандартен SQL. Позволено е в Postgres, но с ограничения и все още е лоша идея да се използва като идентификатор.
„Номерът“ е да се извадят номерата на редовете, така че последователните редове да попадат в една и съща група (grp
) на (player_id, points)
. Тогава филтрирайте тези със 100 точки, обобщавайте за група и връщайте само най-дългия, най-нов резултат за играч.
Основно обяснение на техниката:
Можем да използваме GROUP BY
и DISTINCT ON
в същия SELECT
, GROUP BY
се прилага преди DISTINCT ON
. Разгледайте последователността от събития в SELECT
заявка:
Относно DISTINCT ON
: