Заявка с прозоречни функции
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
В допълнение към това, което вече имахме , имаме нужда от валидни превключватели за ИЗКЛ.
OFF
превключвател, ако е валиден, ако устройството е било включено ON
преди (last_status = 1
) и следващия ON
операция след това идва след OFF
въпросният превключвател (next_id_of_last_status > id
).
Трябва да предвидим специалния случай, че е последното ON
операция, така че проверяваме за NULL
в допълнение (OR next_id_of_last_status IS NULL
).
next_id_of_last_status
идва от същия прозорец, който вземаме last_status
от. Затова въведох допълнителен синтаксис за изрична декларация на прозорец, така че не е нужно да се повтарям:
WINDOW w2 AS (PARTITION BY val ORDER BY id)
И трябва да получим следващия идентификатор за последния статус в подзаявка по-рано (подзаявка t
).
Ако сте разбрали всичко това , не би трябвало да имате проблем с пляскането на lead()
върху тази заявка, за да стигнете до крайната си дестинация. :)
PL/pgSQL функция
След като стане толкова сложно, е време да преминете към процедурна обработка.
Тази сравнително проста plpgsql функция намалява производителността на сложната заявка за функцията на прозореца поради простата причина, че тя трябва да сканира цялата таблица само веднъж.
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$;
Обаждане:
SELECT * FROM valid_t1();