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

Spring SQL-gab over specifik tilstand og korrekt lead()-brug

Forespørgsel med vinduesfunktioner

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0)    OVER (PARTITION BY status ORDER BY id) AS last_val
         ,lag(status, 1, 0) OVER w2 AS last_status
         ,lag(next_id)      OVER w2 AS next_id_of_last_status
   FROM  (
      SELECT *, lead(id) OVER (PARTITION BY status ORDER BY id) AS next_id
      FROM   t1
      ) AS t
   WINDOW w2 AS (PARTITION BY val ORDER BY id)
  ) x
WHERE (last_val <> val OR last_status <> status)
AND   (status = 1 
       OR last_status = 1
          AND ((next_id_of_last_status > id) OR next_id_of_last_status IS NULL)
      )
ORDER  BY id

Ud over hvad vi allerede havde , vi har brug for gyldige OFF-kontakter.

En OFF skift, hvis gyldigt, hvis enheden blev tændt ON før (last_status = 1 ) og den næste ON operation efter det kommer efter OFF den pågældende switch (next_id_of_last_status > id ).

Vi er nødt til at sørge for det specielle tilfælde, at der var den sidste ON operation, så vi tjekker efter NULL derudover (OR next_id_of_last_status IS NULL ).

next_id_of_last_status kommer fra det samme vindue, som vi tager last_status fra. Derfor introducerede jeg yderligere syntaks for eksplicit vindueserklæring, så jeg ikke behøver at gentage mig selv:

WINDOW w2 AS (PARTITION BY val ORDER BY id)

Og vi skal have det næste id for den sidste status i en underforespørgsel tidligere (underforespørgsel t ).

Hvis du har forstået alt det , burde du ikke have problemer med at slå lead() oven på denne forespørgsel for at komme til din endelige destination. :)

PL/pgSQL-funktion

Når det bliver så komplekst, er det tid til at skifte til proceduremæssig behandling.

Denne forholdsvis simple plpgsql-funktion Nukes ydeevnen af ​​den komplekse vinduesfunktionsforespørgsel, af den simple grund, at den kun skal scanne hele tabellen én gang.

CREATE OR REPLACE FUNCTION valid_t1 (OUT t t1)  -- row variable of table type
  RETURNS SETOF t1 LANGUAGE plpgsql AS
$func$
DECLARE
   _last_on int := -1;  -- init with impossible value
BEGIN

FOR t IN
   SELECT * FROM t1 ORDER BY id
LOOP
   IF t.status = 1 THEN
      IF _last_on <> t.val THEN
         RETURN NEXT;
         _last_on := t.val;
      END IF;
   ELSE
      IF _last_on = t.val THEN
         RETURN NEXT;
         _last_on := -1;
      END IF;
   END IF;
END LOOP;

END
$func$;

Ring til:

SELECT * FROM valid_t1();



  1. PHP-meddelelse:Udefineret offset

  2. Multiple Create Trigger-forespørgsel i PDO

  3. Forstå lagringsstørrelser for MySQL TEXT-datatyper

  4. Hvordan tester man tabeller forbundet med fremmednøgler?