Sayangnya, tidak ada solusi yang sesederhana dan sebersih pertanyaan Anda sebelumnya .
Ini harus berhasil:
-
Tambahkan bendera berlebihan
is_publishedkeChildtabelALTER TABLE child ADD column is_published boolean NOT NULL;Jadikan
DEFAULT FALSEatau apa pun yang biasanya Anda miliki di kolom induk saat menyisipkan.
HarusNOT NULLuntuk menghindari celah denganNULLnilai dan defaultMATCH SIMPLEperilaku dalam kunci asing:
Kendala kunci asing dua kolom hanya jika kolom ketiga TIDAK NULL -
Tambahkan (tampaknya tidak ada gunanya, namun) batasan unik pada
parent(parent_id, is_published)ALTER TABLE parent ADD CONSTRAINT parent_fk_uni UNIQUE (parent_id, is_published);Sejak
parent_idadalah kunci utama, kombinasinya akan unik. Tapi itu diperlukan untuk batasan fk berikut. -
Alih-alih merujuk
parent(parent_id)dengan batasan kunci asing , buat kunci asing multi-kolom di(parent_id, is_published)denganON UPDATE CASCADE.
Dengan cara ini, statuschild.is_publisheddipelihara dan ditegakkan oleh sistem secara otomatis dan lebih andal daripada yang dapat Anda terapkan dengan pemicu khusus:ALTER TABLE child ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published) REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE; -
Kemudian tambahkan indeks UNIK parsial seperti pada jawaban Anda sebelumnya.
CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text) WHERE is_published;
Tentu saja, saat menyisipkan baris di child tabel Anda terpaksa menggunakan status parent.is_published saat ini sekarang. Tapi itulah intinya:untuk menegakkan integritas referensial.
Skema lengkap
Atau, alih-alih mengadaptasi skema yang ada, berikut tata letak lengkapnya:
CREATE TABLE parent(
parent_id serial PRIMARY KEY
, is_published bool NOT NULL DEFAULT FALSE
--, more columns ...
, UNIQUE (parent_id, is_published) -- required for fk
);
CREATE TABLE child (
child_id serial PRIMARY KEY
, parent_id integer NOT NULL
, is_published bool NOT NULL DEFAULT FALSE
, txt text
, FOREIGN KEY (parent_id, is_published)
REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE
);
CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
WHERE is_published;