Simplifier la construction sur MATCH SIMPLE
comportement des contraintes fk
Si au moins une colonne de contrainte étrangère multicolonne avec MATCH SIMPLE
par défaut le comportement est NULL
, la contrainte n'est pas appliquée. Vous pouvez en tirer parti pour simplifier considérablement votre conception.
CREATE SCHEMA test;
CREATE TABLE test.status(
status_id integer PRIMARY KEY
,sub bool NOT NULL DEFAULT FALSE -- TRUE .. *can* be sub-status
,UNIQUE (sub, status_id)
);
CREATE TABLE test.entity(
entity_id integer PRIMARY KEY
,status_id integer REFERENCES test.status -- can reference all statuses
,sub bool -- see examples below
,additional_col1 text -- should be NULL for main entities
,additional_col2 text -- should be NULL for main entities
,FOREIGN KEY (sub, status_id) REFERENCES test.status(sub, status_id)
MATCH SIMPLE ON UPDATE CASCADE -- optionally enforce sub-status
);
C'est très bon marché pour stocker des colonnes NULL supplémentaires (pour les entités principales) :
BTW, par documentation :
Données de démonstration :
INSERT INTO test.status VALUES
(1, TRUE)
, (2, TRUE)
, (3, FALSE); -- not valid for sub-entities
INSERT INTO test.entity(entity_id, status_id, sub) VALUES
(11, 1, TRUE) -- sub-entity (can be main, UPDATES to status.sub cascaded)
, (13, 3, FALSE) -- entity (cannot be sub, UPDATES to status.sub cascaded)
, (14, 2, NULL) -- entity (can be sub, UPDATES to status.sub NOT cascaded)
, (15, 3, NULL) -- entity (cannot be sub, UPDATES to status.sub NOT cascaded)
SQL Fiddle (y compris vos tests).
Alternative avec un seul FK
Une autre option serait d'entrer toutes les combinaisons de (status_id, sub)
dans le status
table (il ne peut y en avoir que 2 par status_id
) et n'ont qu'une seule contrainte fk :
CREATE TABLE test.status(
status_id integer
,sub bool DEFAULT FALSE
,PRIMARY KEY (status_id, sub)
);
CREATE TABLE test.entity(
entity_id integer PRIMARY KEY
,status_id integer NOT NULL -- cannot be NULL in this case
,sub bool NOT NULL -- cannot be NULL in this case
,additional_col1 text
,additional_col2 text
,FOREIGN KEY (status_id, sub) REFERENCES test.status
MATCH SIMPLE ON UPDATE CASCADE -- optionally enforce sub-status
);
INSERT INTO test.status VALUES
(1, TRUE) -- can be sub ...
(1, FALSE) -- ... and main
, (2, TRUE)
, (2, FALSE)
, (3, FALSE); -- only main
Etc.
Réponses associées :
- MATCH COMPLET contre MATCH SIMPLE
- Contrainte de clé étrangère à deux colonnes uniquement lorsque la troisième colonne est NOT NULL
- Validation de l'unicité dans la base de données lorsque la validation a une condition sur une autre table
Conserver tous les tableaux
Si vous avez besoin des quatre tables pour une raison qui ne figure pas dans la question, considérez cette solution détaillée à une question très similaire sur dba.SE :
Héritage
... pourrait être une autre option pour ce que vous décrivez. Si vous pouvez vivre avec certaines limitations majeures . Réponse connexe :