PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Validation de l'unicité dans la base de données lorsque la validation a une condition sur une autre table

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 tableau

    ALTER 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 être NOT NULL pour éviter une faille avec NULL valeurs et MATCH 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) avec ON UPDATE CASCADE .
    De cette façon, l'état de child.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;