La tua definizione:
l'attività del gruppo B si svolge sempre dopo l'attività del gruppo A.
.. implica logicamente che vi sia, per utente, 0 o 1 attività B dopo 1 o più attività A. Mai più di 1 B attività in sequenza.
Puoi farlo funzionare con una singola funzione della finestra, DISTINCT ON
e CASE
, che dovrebbe essere il modo più veloce per pochi righe per utente (vedi anche sotto):
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<>gioca qui
Un CASE
SQL l'espressione predefinita è NULL
se non ELSE
branch è stato aggiunto, quindi l'ho mantenuto breve.
Assumendo time
è definito NOT NULL
. Altrimenti, potresti voler aggiungere NULLS LAST
. Perché?
- Ordina per colonna ASC, ma prima i valori NULL?
(activity LIKE 'A%' OR activity LIKE 'B%')
è più dettagliato di activity ~ '^[AB]'
, ma in genere più veloce nelle versioni precedenti di Postgres. Informazioni sulla corrispondenza dei modelli:
- Corrispondenza del modello con LIKE, SIMILAR TO o espressioni regolari in PostgreSQL
Funzioni della finestra condizionale?
In realtà è possibile . Puoi combinare il FILTER
aggregato clausola con OVER
clausola delle funzioni della finestra. Tuttavia :
-
Il
FILTER
la clausola stessa può funzionare solo con i valori della riga corrente. -
Ancora più importante,
FILTER
non è implementato per funzioni pure genuine comelead()
olag()
(fino a Postgres 13) - solo per funzioni aggregate.
Se provi:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Postgres ti dirà:
FILTER is not implemented for non-aggregate window functions
Informazioni su FILTER
:
- Colonna aggregata con filtri (distinti) aggiuntivi
- Riferimento alla riga corrente nella clausola FILTER della funzione finestra
Prestazioni
Per pochi utenti con pochi righe per utente, praticamente qualsiasi la query è veloce, anche senza indice.
Per molti utenti e pochi righe per utente, la prima query sopra dovrebbe essere più veloce. Vedi:
- Seleziona la prima riga in ogni gruppo GROUP BY?
Per molti righe per utente, ci sono (potenzialmente molto ) tecniche più veloci, a seconda dei dettagli della tua configurazione. Vedi:
- Ottimizza la query GROUP BY per recuperare l'ultima riga per utente