PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Eindeutigkeitsvalidierung in der Datenbank, wenn die Validierung eine Bedingung für eine andere Tabelle hat

Leider gibt es keine so einfache und saubere Lösung wie für Ihre vorherige Frage .

Das sollte funktionieren:

  • Fügen Sie ein Redundanz-Flag is_published hinzu zum Child Tabelle

    ALTER TABLE child ADD column is_published boolean NOT NULL;
    

    Setzen Sie es auf DEFAULT FALSE oder was auch immer Sie normalerweise beim Einfügen in übergeordneten Spalten haben.
    Es muss NOT NULL sein um eine Lücke mit NULL zu vermeiden Werte und Standard MATCH SIMPLE Verhalten in Fremdschlüsseln:
    Fremdschlüsselbeschränkung für zwei Spalten nur, wenn die dritte Spalte NICHT NULL ist

  • Fügen Sie eine (scheinbar sinnlose, aber dennoch) eindeutige Einschränkung für parent(parent_id, is_published) hinzu

    ALTER TABLE parent ADD CONSTRAINT parent_fk_uni
    UNIQUE (parent_id, is_published);
    

    Seit parent_id der Primärschlüssel ist, wäre die Kombination in jedem Fall eindeutig. Aber das ist für die folgende fk-Einschränkung erforderlich.

  • Statt auf parent(parent_id) zu verweisen mit einer einfachen Fremdschlüsselbeschränkung , erstellen Sie einen mehrspaltigen Fremdschlüssel für (parent_id, is_published) mit ON UPDATE CASCADE .
    Auf diese Weise wird der Status von child.is_published angezeigt wird vom System automatisch und zuverlässiger gepflegt und durchgesetzt, als Sie es mit benutzerdefinierten Triggern implementieren könnten:

    ALTER TABLE child
    ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published)
    REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
    
  • Fügen Sie dann einen partial UNIQUE index hinzu wie in deiner vorherigen Antwort.

    CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
    WHERE is_published;
    

Natürlich beim Einfügen von Zeilen in das child Tabelle sind Sie gezwungen, den aktuellen Stand von parent.is_published zu verwenden jetzt. Aber das ist der Punkt:referentielle Integrität zu erzwingen.

Vollständiges Schema

Oder, anstatt ein bestehendes Schema anzupassen, hier das komplette Layout:

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;