ウィンドウ関数を使用したクエリ
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
すでに持っていたもの に加えて 、有効なオフスイッチが必要です。
オフコード> デバイスが
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)
そして、以前にサブクエリの最後のステータスの次のIDを取得する必要があります(サブクエリ t
。
すべてを理解している場合 、 Lead()
を叩くのに問題はないはずです このクエリに加えて、最終目的地に到達します。 :)
PL/pgSQL関数
これが複雑になったら、手続き型処理に切り替えます。
この比較的単純なplpgsql関数 テーブル全体を1回だけスキャンする必要があるという単純な理由から、複雑なウィンドウ関数クエリのパフォーマンスを低下させます。
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();