Nếu bạn chỉ cần 2 hoặc 3 loại (thực vật / metazoa / vi khuẩn) và bạn muốn mô hình hóa mối quan hệ XOR, có thể một "vòng cung" là giải pháp cho bạn. Ưu điểm: không cần kích hoạt. Sơ đồ ví dụ có thể được tìm thấy [ở đây] [1]. Trong tình huống của bạn, bảng "thùng chứa" sẽ có 3 cột với ràng buộc KIỂM TRA, cho phép thực vật hoặc động vật hoặc vi khuẩn.
Điều này có lẽ không phù hợp nếu có nhu cầu phân biệt giữa rất nhiều loại (ví dụ: chi, loài, phân loài) trong tương lai. Tuy nhiên, đối với 2-3 nhóm / danh mục, điều này có thể thực hiện thủ thuật.
CẬP NHẬT: Lấy cảm hứng từ các đề xuất và nhận xét của người đóng góp, một giải pháp khác cho phép nhiều đơn vị phân loại (nhóm sinh vật liên quan, được phân loại bởi nhà sinh vật học) và tránh các tên bảng "cụ thể" (PostgreQuery 9.5).
Mã 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) ;
Dữ liệu kiểm tra:
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');
Kiểm tra:
-- 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');
Cảm ơn @RDFozz và @Evan Carroll và @ypercube vì sự đóng góp và kiên nhẫn của họ (đọc / sửa câu trả lời của tôi).