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 :
-
FILTER
satsen 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