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

Überspringen Sie die SQL-Lücke über eine bestimmte Bedingung und die ordnungsgemäße Verwendung von lead()

Abfrage mit Fensterfunktionen

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

Zusätzlich zu was wir bereits hatten , brauchen wir gültige AUS-Schalter.

Ein OFF Schalter falls gültig, wenn das Gerät ON war davor (last_status = 1 ) und das nächste ON Betrieb danach kommt nach dem OFF betreffenden Schalter (next_id_of_last_status > id ).

Wir müssen für den Sonderfall sorgen, dass der letzte ON war Operation, also prüfen wir auf NULL zusätzlich (OR next_id_of_last_status IS NULL ).

Der next_id_of_last_status kommt aus demselben Fenster, aus dem wir last_status nehmen aus. Deshalb habe ich eine zusätzliche Syntax für die explizite Fensterdeklaration eingeführt, damit ich mich nicht wiederholen muss:

WINDOW w2 AS (PARTITION BY val ORDER BY id)

Und wir müssen die nächste ID für den letzten Status in einer früheren Unterabfrage erhalten (Unterabfrage t ).

Wenn Sie das alles verstanden haben , sollten Sie kein Problem damit haben, lead() zu schlagen zusätzlich zu dieser Abfrage, um zu Ihrem endgültigen Ziel zu gelangen. :)

PL/pgSQL-Funktion

Sobald es so komplex wird, ist es an der Zeit, zur prozeduralen Verarbeitung überzugehen.

Diese vergleichsweise einfache plpgsql-Funktion verringert die Leistung der komplexen Fensterfunktion query, aus dem einfachen Grund, dass sie die gesamte Tabelle nur einmal scannen muss.

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$;

Aufruf:

SELECT * FROM valid_t1();