Consulta com funções de janela
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
Além do o que já tínhamos , precisamos de chaves OFF válidas.
Um
OFF
switch se válido se o dispositivo foi ligado ON
antes (last_status = 1
) e o próximo ON
operação depois que vem depois do OFF
switch em questão (next_id_of_last_status > id
). Temos que prever o caso especial de que foi o último
ON
operação, então verificamos se há NULL
além disso (OR next_id_of_last_status IS NULL
). O
next_id_of_last_status
vem da mesma janela que pegamos last_status
a partir de. Portanto, introduzi sintaxe adicional para declaração de janela explícita, para não precisar me repetir:WINDOW w2 AS (PARTITION BY val ORDER BY id)
E precisamos obter o próximo id para o último status em uma subconsulta anterior (subconsulta
t
). Se você entendeu tudo isso , você não deve ter problemas em dar um tapa em
lead()
em cima desta consulta para chegar ao seu destino final. :) Função PL/pgSQL
Uma vez que fica tão complexo, é hora de mudar para o processamento processual.
Esta função plpgsql comparativamente simples elimina o desempenho da consulta de função de janela complexa, pelo simples motivo de que ela precisa varrer toda a tabela apenas uma vez.
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$;
Ligar:
SELECT * FROM valid_t1();