Tyvärr finns det ingen lösning riktigt så enkel och ren som för din tidigare fråga .
Detta borde göra jobbet:
-
Lägg till en redundant flagga
is_published
tillChild
bordALTER TABLE child ADD column is_published boolean NOT NULL;
Gör det till
DEFAULT FALSE
eller vad du vanligtvis har i överordnade kolumner när du infogar.
Det måste varaNOT NULL
för att undvika ett kryphål medNULL
värden och standardMATCH SIMPLE
beteende i främmande nycklar:
Tvåkolumns främmande nyckelbegränsning endast när den tredje kolumnen INTE är NULL -
Lägg till en (till synes meningslös men ändå) unik begränsning på
parent(parent_id, is_published)
ALTER TABLE parent ADD CONSTRAINT parent_fk_uni UNIQUE (parent_id, is_published);
Sedan
parent_id
är den primära nyckeln, skulle kombinationen vara unik oavsett. Men det krävs för följande fk-begränsning. -
Istället för att referera till
parent(parent_id)
med en enkel restriktion för främmande nyckel , skapa en främmande nyckel med flera kolumner på(parent_id, is_published)
medON UPDATE CASCADE
.
På detta sätt är tillståndet förchild.is_published
underhålls och upprätthålls av systemet automatiskt och mer tillförlitligt än vad du skulle kunna implementera med anpassade utlösare:ALTER TABLE child ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published) REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
-
Lägg sedan till ett partiellt UNIKT index som i ditt tidigare svar.
CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text) WHERE is_published;
Naturligtvis när du infogar rader i child
tabell du tvingas använda det nuvarande tillståndet för parent.is_published
nu. Men det är poängen:att upprätthålla referensintegritet.
Fullständigt schema
Eller, istället för att anpassa ett befintligt schema, här är den fullständiga layouten:
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;