Fråga med fönsterfunktioner
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
Förutom det vi redan hade , vi behöver giltiga AV-brytare.
En OFF
växla om giltigt om enheten var ON
före (last_status = 1
) och nästa ON
operation efter det kommer efter OFF
växeln i fråga (next_id_of_last_status > id
).
Vi måste ta hänsyn till det speciella fallet att det var den senaste ON
operation, så vi letar efter NULL
dessutom (OR next_id_of_last_status IS NULL
).
next_id_of_last_status
kommer från samma fönster som vi tar last_status
från. Därför introducerade jag ytterligare syntax för explicit fönsterdeklaration, så jag behöver inte upprepa mig:
WINDOW w2 AS (PARTITION BY val ORDER BY id)
Och vi måste få nästa id för den senaste statusen i en underfråga tidigare (underfråga t
).
Om du har förstått allt det , du borde inte ha några problem med att slå lead()
ovanpå denna fråga för att komma till din slutdestination. :)
PL/pgSQL-funktion
När det blir så här komplext är det dags att byta till processuell bearbetning.
Denna jämförelsevis enkla plpgsql-funktion kärnar ur prestandan för den komplexa fönsterfunktionsfrågan, av den enkla anledningen att den bara måste skanna hela tabellen en gång.
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:
SELECT * FROM valid_t1();