Salah satu solusinya adalah memiliki tabel kedua yang digunakan untuk mendeteksi bentrokan, dan mengisinya dengan pemicu. Menggunakan skema yang Anda tambahkan ke pertanyaan:
CREATE TABLE medicinal_product_date_map(
aic_code char(9) NOT NULL,
applicable_date date NOT NULL,
UNIQUE(aic_code, applicable_date));
(catatan:ini adalah upaya kedua karena salah membaca persyaratan Anda pada putaran pertama. semoga kali ini benar).
Beberapa fungsi untuk memelihara tabel ini:
CREATE FUNCTION add_medicinal_product_date_range(aic_code_in char(9), start_date date, end_date date)
RETURNS void STRICT VOLATILE LANGUAGE sql AS $$
INSERT INTO medicinal_product_date_map
SELECT $1, $2 + offset
FROM generate_series(0, $3 - $2)
$$;
CREATE FUNCTION clr_medicinal_product_date_range(aic_code_in char(9), start_date date, end_date date)
RETURNS void STRICT VOLATILE LANGUAGE sql AS $$
DELETE FROM medicinal_product_date_map
WHERE aic_code = $1 AND applicable_date BETWEEN $2 AND $3
$$;
Dan isi tabel pertama kali dengan:
SELECT count(add_medicinal_product_date_range(aic_code, vs, ve))
FROM medicinal_products;
Sekarang buat pemicu untuk mengisi peta tanggal setelah perubahan ke obat_produk:setelah memasukkan panggilan add_, setelah memperbarui panggilan clr_ (nilai lama) dan add_ (nilai baru), setelah menghapus panggilan clr_.
CREATE FUNCTION sync_medicinal_product_date_map()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN
PERFORM clr_medicinal_product_date_range(OLD.aic_code, OLD.vs, OLD.ve);
END IF;
IF TG_OP = 'UPDATE' OR TG_OP = 'INSERT' THEN
PERFORM add_medicinal_product_date_range(NEW.aic_code, NEW.vs, NEW.ve);
END IF;
RETURN NULL;
END;
$$;
CREATE TRIGGER sync_date_map
AFTER INSERT OR UPDATE OR DELETE ON medicinal_products
FOR EACH ROW EXECUTE PROCEDURE sync_medicinal_product_date_map();
Batasan keunikan pada medicine_product_date_map akan menjebak setiap produk yang ditambahkan dengan kode yang sama pada hari yang sama:
[email protected]@[local] =# INSERT INTO medicinal_products VALUES ('1','A','2010-01-01','2010-04-01');
INSERT 0 1
[email protected]@[local] =# INSERT INTO medicinal_products VALUES ('1','A','2010-03-01','2010-06-01');
ERROR: duplicate key value violates unique constraint "medicinal_product_date_map_aic_code_applicable_date_key"
DETAIL: Key (aic_code, applicable_date)=(1 , 2010-03-01) already exists.
CONTEXT: SQL function "add_medicinal_product_date_range" statement 1
SQL statement "SELECT add_medicinal_product_date_range(NEW.aic_code, NEW.vs, NEW.ve)"
PL/pgSQL function "sync_medicinal_product_date_map" line 6 at PERFORM
Ini tergantung pada nilai yang diperiksa untuk memiliki ruang diskrit - itulah sebabnya saya bertanya tentang tanggal vs cap waktu. Meskipun stempel waktu, secara teknis, diskrit karena Postgresql hanya menyimpan resolusi mikrodetik, menambahkan entri ke tabel peta untuk setiap mikrodetik produk tidak praktis.
Karena itu, Anda mungkin juga bisa lolos dengan sesuatu yang lebih baik daripada pemindaian tabel penuh untuk memeriksa interval stempel waktu yang tumpang tindih, dengan beberapa tipu daya untuk mencari hanya interval pertama tidak setelah atau tidak sebelum ... namun, untuk ruang diskrit yang mudah Saya lebih suka pendekatan ini yang IME juga dapat berguna untuk hal-hal lain juga (misalnya laporan yang perlu dengan cepat menemukan produk mana yang berlaku pada hari tertentu).
Saya juga menyukai pendekatan ini karena rasanya tepat untuk memanfaatkan mekanisme batasan keunikan database dengan cara ini. Juga, saya merasa itu akan lebih dapat diandalkan dalam konteks pembaruan bersamaan ke tabel master:tanpa mengunci tabel terhadap pembaruan bersamaan, pemicu validasi mungkin tidak melihat konflik dan mengizinkan penyisipan dalam dua sesi bersamaan, yaitu kemudian terlihat konflik ketika efek kedua transaksi terlihat.