Din definition:
aktivitet från grupp B sker alltid efter aktivitet från grupp A.
.. innebär logiskt att det finns, per användare, 0 eller 1 B-aktivitet efter 1 eller flera A-aktiviteter. Aldrig mer än 1 B aktiviteter i följd.
Du kan få det att fungera med en enda fönsterfunktion, DISTINCT ON och CASE , vilket borde vara det snabbaste sättet för få rader per användare (se även nedan):
SELECT name
, CASE WHEN a2 LIKE 'B%' THEN a1 ELSE a2 END AS activity
, CASE WHEN a2 LIKE 'B%' THEN a2 END AS next_activity
FROM (
SELECT DISTINCT ON (name)
name
, lead(activity) OVER (PARTITION BY name ORDER BY time DESC) AS a1
, activity AS a2
FROM t
WHERE (activity LIKE 'A%' OR activity LIKE 'B%')
ORDER BY name, time DESC
) sub;
db<>spela här
En SQL CASE uttryck har som standard NULL om ingen ELSE gren läggs till, så jag höll det kort.
Förutsatt time är definierad NOT NULL . Annars kanske du vill lägga till NULLS LAST . Varför?
- Sortera efter kolumn ASC, men NULL-värden först?
(activity LIKE 'A%' OR activity LIKE 'B%') är mer utförlig än activity ~ '^[AB]' , men vanligtvis snabbare i äldre versioner av Postgres. Om mönstermatchning:
- Mönstermatchning med LIKE, SIMILAR TO eller reguljära uttryck i PostgreSQL
Villkorliga fönsterfunktioner?
Det är faktiskt möjligt . Du kan kombinera det sammanlagda FILTER sats med OVER klausul av fönsterfunktioner. Men :
-
FILTERsatsen i sig kan bara fungera med värden från den aktuella raden. -
Ännu viktigare,
FILTERär inte implementerat för rena äkta funktioner somlead()ellerlag()(upp till Postgres 13) - endast för aggregerade funktioner.
Om du försöker:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Postgres kommer att berätta:
FILTER is not implemented for non-aggregate window functions
Om FILTER :
- Aggregera kolumner med ytterligare (distinkta) filter
- Refererar till aktuell rad i FILTER-satsen i fönsterfunktionen
Prestanda
För få användare med få rader per användare, i stort sett alla frågan är snabb, även utan index.
För många användare och få rader per användare, bör den första frågan ovan vara snabbast. Se:
- Välj första raden i varje GROUP BY-grupp?
För många rader per användare, det finns (potentiellt mycket ) snabbare tekniker, beroende på detaljer i din installation. Se:
- Optimera GROUP BY-frågan för att hämta den senaste raden per användare