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 :