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

Erkennen Sie SQL Island über mehrere Parameter und Bedingungen

Antwort auf aktualisierte Frage

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0) OVER (PARTITION BY status ORDER BY id) last_val
         ,lag(status) OVER (PARTITION BY val ORDER BY id) last_status
   FROM   t1
   ) x
WHERE  status = 1
AND    (last_val <> val OR last_status = 0)

Wie?

Wie zuvor, aber dieses Mal zwei Fensterfunktionen kombinieren. Das Einschalten eines Geräts qualifiziert sich, wenn ..
1. das zuletzt eingeschaltete Gerät war ein anderes eins.
2. oder dasselbe Gerät wurde ausgeschaltet in seinem letzten Eintrag. Der Eckfall mit NULL für die erste Zeile der Partition ist irrelevant, weil dann die Zeile bereits in 1. qualifiziert ist

Antwort für Originalversion der Frage.

Wenn Sie Ihre Aufgabe richtig verstehen, reicht diese einfache Abfrage:

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0) OVER (ORDER BY id) last_on
   FROM   t1
   WHERE  status = 1
   ) x
WHERE  last_on <> val

Gibt wie angefordert die Zeilen 1, 3, 6, 7 zurück.

Wie?

Die Unterabfrage ignoriert alle Abschaltungen, da dies nach Ihrer Beschreibung nur Rauschen ist. Hinterlässt Einträge, wo ein Gerät eingeschaltet ist. Darunter werden nur diejenigen Einträge disqualifiziert, bei denen das gleiche Gerät bereits eingeschaltet war (der letzte Eintrag schaltete ein). Verwenden Sie die Fensterfunktion lag() dafür. Insbesondere gebe ich 0 an als Standard, um den Sonderfall der ersten Zeile abzudecken - vorausgesetzt, es gibt kein Gerät mit val = 0 .
Wenn ja, wählen Sie eine andere unmögliche Zahl.
Wenn keine Zahl unmöglich ist, belassen Sie den Sonderfall bei NULL mit lag(val) OVER ... und in der äußeren Abfrage prüfen mit:

WHERE last_on IS DISTINCT FROM val