PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Bedingte Lead/Lag-Funktion PostgreSQL?

Ihre Definition:

Aktivität aus Gruppe B findet immer nach Aktivität aus Gruppe A statt.

.. impliziert logischerweise, dass es pro Benutzer 0 oder 1 B-Aktivität nach 1 oder mehr A-Aktivitäten gibt. Nie mehr als 1 B Aktivitäten hintereinander.

Sie können es mit einer einzelnen Fensterfunktion, DISTINCT ON, zum Laufen bringen und CASE , was für wenige der schnellste Weg sein sollte Zeilen pro Benutzer (siehe auch unten):

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<>hier fummeln

Ein SQL CASE Ausdruck ist standardmäßig NULL wenn kein ELSE Verzweigung hinzugefügt, also habe ich mich kurz gehalten.

Angenommen time ist NOT NULL definiert . Andernfalls möchten Sie vielleicht NULLS LAST hinzufügen . Warum?

  • Nach Spalte ASC sortieren, aber zuerst NULL-Werte?

(activity LIKE 'A%' OR activity LIKE 'B%') ist ausführlicher als activity ~ '^[AB]' , aber normalerweise schneller in älteren Versionen von Postgres. Über den Musterabgleich:

  • Mustervergleich mit LIKE, SIMILAR TO oder regulären Ausdrücken in PostgreSQL

Bedingte Fensterfunktionen?

Das ist tatsächlich möglich . Sie können das Aggregat FILTER kombinieren -Klausel mit dem OVER Klausel von Fensterfunktionen. Allerdings :

  1. Der FILTER -Klausel selbst kann nur mit Werten aus der aktuellen Zeile arbeiten.

  2. Noch wichtiger, FILTER ist für reine echte Funktionen wie lead() nicht implementiert oder lag() (bis Postgres 13) - nur für Aggregatfunktionen.

Wenn Sie versuchen:

lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity

Postgres sagt Ihnen:

FILTER is not implemented for non-aggregate window functions

Über FILTER :

  • Aggregierte Spalten mit zusätzlichen (unterschiedlichen) Filtern
  • Verweis auf die aktuelle Zeile in der FILTER-Klausel der Fensterfunktion

Leistung

Für wenige Benutzer mit wenigen Zeilen pro Benutzer, so ziemlich beliebig Abfrage ist schnell, auch ohne Index.

Für viele Benutzer und wenige Zeilen pro Benutzer, die erste obige Abfrage sollte am schnellsten sein. Siehe:

  • Erste Zeile in jeder GROUP BY-Gruppe auswählen?

Für viele Zeilen pro Benutzer gibt es (möglicherweise viele ) schnellere Techniken, abhängig von den Details Ihres Setups. Siehe:

  • Optimieren Sie die GROUP BY-Abfrage, um die neueste Zeile pro Benutzer abzurufen