sql >> Databasteknik >  >> RDS >> PostgreSQL

Villkorlig lead/lag-funktion PostgreSQL?

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

  1. FILTER satsen i sig kan bara fungera med värden från den aktuella raden.

  2. Ännu viktigare, FILTER är inte implementerat för rena äkta funktioner som lead() eller lag() (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 användare med rader per användare, i stort sett alla frågan är snabb, även utan index.

För många användare och 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


  1. SQL Server VÄLJ SISTA N rader

  2. Hur man tar bort ledande och efterföljande blanksteg i SQL Server – TRIM()

  3. Välj rader som inte finns i andra tabeller

  4. Ogiltigt gemensamt användar- eller rollnamn