Kueri dengan fungsi jendela
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
Selain apa yang sudah kami miliki , kita membutuhkan tombol OFF yang valid.
Sebuah OFF
beralih jika valid jika perangkat diaktifkan ON
sebelumnya (last_status = 1
) dan ON
berikutnya operasi setelah itu datang setelah OFF
alihkan pertanyaan (next_id_of_last_status > id
).
Kami harus menyediakan kasus khusus yang ada ON
terakhir operasi, jadi kami memeriksa NULL
sebagai tambahan (OR next_id_of_last_status IS NULL
).
next_id_of_last_status
berasal dari jendela yang sama dengan yang kita ambil last_status
dari. Oleh karena itu saya memperkenalkan sintaks tambahan untuk deklarasi jendela eksplisit, jadi saya tidak perlu mengulang sendiri:
WINDOW w2 AS (PARTITION BY val ORDER BY id)
Dan kita perlu mendapatkan id selanjutnya untuk status terakhir di subquery tadi (subquery t
).
Jika Anda telah memahami semua itu , Anda tidak akan kesulitan menampar lead()
di atas kueri ini untuk mencapai tujuan akhir Anda. :)
Fungsi PL/pgSQL
Setelah menjadi kompleks ini, saatnya beralih ke pemrosesan prosedural.
fungsi plpgsql yang relatif sederhana ini menghentikan kinerja kueri fungsi jendela yang kompleks, karena alasan sederhana bahwa ia harus memindai seluruh tabel hanya sekali.
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$;
Telepon:
SELECT * FROM valid_t1();