我有一个具有多种实体类型的实体表和一个实体关系表,该表需要强制其只包含相同类型的实体之间的关系。
目前,我有两种解决方法:
CREATE TABLE entity (
id uuid PRIMARY KEY,
type my_enum_type NOT NULL,
-- … more
);
CREATE TABLE relation (
id uuid PRIMARY KEY,
x uuid REFERENCES entity NOT NULL,
y uuid REFERENCES entity NOT NULL,
CHECK(entity(x).type = entity(y).type)
-- Doesn't work because CHECK cannot reference other tables.
);
幸运的是,我目前只有两种类型,并且不希望很快改变。但是继承不能与外键很好地混合,因此它变得非常冗长:
CREATE TABLE entity (
id uuid PRIMARY KEY,
-- … more fields
);
CREATE TABLE entity_a (
PRIMARY KEY (id)
) INHERITS (entity);
CREATE TABLE entity_b (
PRIMARY KEY (id)
) INHERITS (entity);
CREATE TABLE relation (
id uuid PRIMARY KEY,
x uuid NOT NULL,
y uuid NOT NULL,
-- … more fields
);
CREATE TABLE relation_a (
PRIMARY KEY (id),
FOREIGN KEY (x) REFERENCES entity_a (id),
FOREIGN KEY (y) REFERENCES entity_a (id)
) INHERITS (relation);
CREATE TABLE relation_b (
PRIMARY KEY (id),
FOREIGN KEY (x) REFERENCES entity_b (id),
FOREIGN KEY (y) REFERENCES entity_b (id)
) INHERITS (relation);
第二种方法肯定具有它可以工作的优点,但是它是冗长的,不可扩展的,并且与完全独立的表定义相比,唯一的优点是它避免了复制所有其他字段(然后可能忘记了在两个地方都进行更新)
关于如何更优雅地解决此问题的任何建议?
答案 0 :(得分:1)
以下语句将为您的解决方案1)添加约束,以便始终满足条件:
/* we need a (redundant) UNIQUE constraint as target for foreign keys */
ALTER TABLE entity ADD UNIQUE (type, id);
/* add a (redundant) "type" column and fill it from "entity" */
ALTER TABLE relation ADD type my_enum_type;
UPDATE relation SET type = e.type
FROM entity AS e
WHERE relation.x = e.id;
ALTER TABLE relation ALTER type SET NOT NULL;
/* now we can add foreign keys that guarantee your condition */
ALTER TABLE relation ADD FOREIGN KEY (type, x) REFERENCES entity (type, id);
ALTER TABLE relation ADD FOREIGN KEY (type, y) REFERENCES entity (type, id);
/* remove the bloat (optional) */
VACUUM (FULL) relation;
是的,它添加了一个多余的列和一个多余的约束,但是我认为这是确保您的状况最优雅自然的方法。