PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Funzione lead/lag condizionale PostgreSQL?

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 :

  1. Il FILTER la clausola stessa può funzionare solo con i valori della riga corrente.

  2. Ancora più importante, FILTER non è implementato per funzioni pure genuine come lead() o lag() (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