Malheureusement, il n'y a pas de solution aussi simple et propre que pour votre question précédente .
Cela devrait faire l'affaire :
-
Ajouter un indicateur redondant
is_published
à l'Child
tableauALTER TABLE child ADD column is_published boolean NOT NULL;
Faites-en
DEFAULT FALSE
ou tout ce que vous avez généralement dans les colonnes parentes lors de l'insertion.
Il doit êtreNOT NULL
pour éviter une faille avecNULL
valeurs etMATCH SIMPLE
par défaut comportement dans les clés étrangères :
Contrainte de clé étrangère à deux colonnes uniquement lorsque la troisième colonne est NOT NULL -
Ajouter une contrainte unique (apparemment inutile, mais pourtant) sur
parent(parent_id, is_published)
ALTER TABLE parent ADD CONSTRAINT parent_fk_uni UNIQUE (parent_id, is_published);
Depuis
parent_id
est la clé primaire, la combinaison serait unique dans les deux cas. Mais cela est requis pour la contrainte fk suivante. -
Au lieu de faire référence à
parent(parent_id)
avec une simple contrainte de clé étrangère , créez une clé étrangère multi-colonnes sur(parent_id, is_published)
avecON UPDATE CASCADE
.
De cette façon, l'état dechild.is_published
est maintenu et appliqué par le système automatiquement et de manière plus fiable que ce que vous pourriez implémenter avec des déclencheurs personnalisés :ALTER TABLE child ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published) REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
-
Ajoutez ensuite un index UNIQUE partiel comme dans votre réponse précédente.
CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text) WHERE is_published;
Bien sûr, lors de l'insertion de lignes dans le child
table, vous êtes obligé d'utiliser l'état actuel de parent.is_published
à présent. Mais c'est là le but :faire respecter l'intégrité référentielle.
Schéma complet
Ou, au lieu d'adapter un schéma existant, voici la mise en page complète :
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;