在数据库中模拟Tagged union的最佳方法是什么?我在谈论这样的事情:
create table t1 { vehicle_id INTEGER NOT NULL REFERENCES car(id) OR motor(id) -- not valid ... }
其中vehicle_id将在汽车表或电机表中为id,并且它将知道哪个.
(假设电动机和汽车桌没有任何共同点
有些人使用一种名为Polymorphic Associations的设计来执行此操作,允许vehicle_id
包含存在于car
或motor
表中的值.然后添加一个vehicle_type
命名t1
引用中给定行的表的名称.
问题是,如果执行此操作,则无法声明真正的SQL外键约束.SQL中不支持具有多个引用目标的外键.还有其他问题,但缺乏参照完整性已经成为一种交易破坏者.
更好的设计是从OO设计中借用两种常见超类型的概念,car
并且motor
:
CREATE TABLE Identifiable ( id SERIAL PRIMARY KEY );
然后t1
引用这个超类型表:
CREATE TABLE t1 ( vehicle_id INTEGER NOT NULL, FOREIGN KEY (vehicle_id) REFERENCES identifiable(id) ... );
并且还使子类型引用其父类型.请注意,子类型的主键不是自动递增.父超类型负责分配新的id值,子节点只引用该值.
CREATE TABLE car ( id INTEGER NOT NULL, FOREIGN KEY (id) REFERENCES identifiable(id) ... ); CREATE TABLE motor ( id INTEGER NOT NULL, FOREIGN KEY (id) REFERENCES identifiable(id) ... );
现在,您可以拥有真正的参照完整性,但也支持具有各自属性的多个子类型表.
@Quassnoi的答案还显示了一种强制不相交的子类型的方法.也就是说,你想阻止都car
和motor
在它们的父父表引用同一行.当我这样做时,我使用单列主键,Identifiable.id
但也声明了一个UNIQUE
键Identifiable.(id, type)
.外键中的car
和motor
可以引用两列唯一键而不是主键.
CREATE TABLE vehicle (type INT NOT NULL, id INT NOT NULL, PRIMARY KEY (type, id) ) CREATE TABLE car (type INT NOT NULL DEFAULT 1, id INT NOT NULL PRIMARY KEY, CHECK(type = 1), FOREIGN KEY (type, id) REFERENCES vehicle ) CREATE TABLE motorcycle (type INT NOT NULL DEFAULT 2, id INT NOT NULL PRIMARY KEY, CHECK(type = 2), FOREIGN KEY (type, id) REFERENCES vehicle ) CREATE TABLE t1 ( ... vehicle_type INT NOT NULL, vehicle_id INT NOT NULL, FOREIGN KEY (vehicle_type, vehicle_id) REFERENCES vehicle ... )