Si vous n'avez besoin que de 2 ou 3 catégories (plantes / métazoaires / bactéries) et que vous souhaitez modéliser une relation XOR, peut-être qu'un "arc" est la solution pour vous. Avantage: pas besoin de déclencheurs. Des exemples de diagrammes peuvent être trouvés [ici] [1]. Dans votre situation, la table "containers" aurait 3 colonnes avec une contrainte CHECK, permettant soit une plante, soit un animal, soit une bactérie.
Cela n'est probablement pas approprié s'il sera nécessaire de faire la distinction entre de nombreuses catégories (par exemple genres, espèces, sous-espèces) à l'avenir. Cependant, pour 2-3 groupes / catégories, cela peut faire l'affaire.
MISE À JOUR: Inspirée par les suggestions et commentaires du contributeur, une solution différente qui permet de nombreux taxons (groupes d'organismes apparentés, classés par biologiste), et évite les noms de table "spécifiques" (PostgreSQL 9.5).
Code DDL:
-- containers: may have more columns eg for temperature, humidity etc
create table containers (
ctr_name varchar(64) unique
);
-- taxonomy - have as many taxa as needed (not just plants/animals/bacteria)
create table taxa (
t_name varchar(64) unique
);
create table organisms (
o_id integer primary key
, o_name varchar(64)
, t_name varchar(64) references taxa(t_name)
, unique (o_id, t_name)
);
-- table for mapping containers to organisms and (their) taxon,
-- each container contains organisms of one and the same taxon
create table collection (
ctr_name varchar(64) references containers(ctr_name)
, o_id integer
, t_name varchar(64)
, unique (ctr_name, o_id)
);
-- exclude : taxa that are different from those already in a container
alter table collection
add exclude using gist (ctr_name with =, t_name with <>);
-- FK : is the o_id <-> t_name (organism-taxon) mapping correct?
alter table collection
add constraint taxon_fkey
foreign key (o_id, t_name) references organisms (o_id, t_name) ;
Données de test:
insert into containers values ('container_a'),('container_b'),('container_c');
insert into taxa values('t:plant'),('t:animal'),('t:bacterium');
insert into organisms values
(1, 'p1', 't:plant'),(2, 'p2', 't:plant'),(3, 'p3', 't:plant'),
(11, 'a1', 't:animal'),(22, 'a1', 't:animal'),(33, 'a1', 't:animal'),
(111, 'b1', 't:bacterium'),(222, 'b1', 't:bacterium'),(333, 'b1', 't:bacterium');
Essai:
-- several plants can be in one and the same container (3 inserts succeed)
insert into collection values ('container_a', 1, 't:plant');
insert into collection values ('container_a', 2, 't:plant');
insert into collection values ('container_a', 3, 't:plant');
-- 3 inserts that fail:
-- organism id in a container must be UNIQUE
insert into collection values ('container_a', 1, 't:plant');
-- bacteria not allowed in container_a, populated by plants (EXCLUSION at work)
insert into collection values ('container_a', 333, 't:bacterium');
-- organism with id 333 is NOT a plant -> insert prevented by FK
insert into collection values ('container_a', 333, 't:plant');
Merci à @RDFozz et @Evan Carroll et @ypercube pour leur contribution et leur patience (lecture / correction de mes réponses).