多表唯一约束

13
假设我们有这些表:
```sql CREATE TABLE A ( id SERIAL NOT NULL PRIMARY KEY ); CREATE TABLE B ( id SERIAL NOT NULL PRIMARY KEY ); CREATE TABLE Parent ( id SERIAL NOT NULL PRIMARY KEY, aId INTEGER NOT NULL REFERENCES A (id), bId INTEGER NOT NULL REFERENCES B (id), UNIQUE(aId, bId) ); CREATE TABLE Child ( parentId INTEGER NOT NULL REFERENCES Parent (id), createdOn TIMESTAMP NOT NULL ); ```
是否可以在 Child 上创建一个唯一约束,使得对于 Child 中的所有行,最多只有一行引用了具有某个值的 aIdParent?换句话说,我能否创建一个唯一约束,以便上述表的连接没有重复的 aId?我认为不行 - 我能找到的每个数据库的语法似乎都与每个约束绑定单个表 - 但这可能是我缺乏想象力。(当然,将 aId 包含在 Child 中是一种解决方法。)

3
您可以在插入或更新时使用触发器来执行和响应您的约束逻辑,但我认为触发器应该是绝对的最后手段 —— 我宁愿在业务层面上解决这个问题。 - Brian Webster
1
我同意hamlin11的观点,但我更倾向于在大多数情况下不要在业务层完成此操作,而是使用数据库触发器。 - Kuberchaun
3
如果约束条件过于简单,将其放在业务层是最糟糕的选择。此时触发器是正确的选择。当然,必须编写一个正确且性能良好的触发器(糟糕的触发器会让触发器声名狼藉)。 - HLGEM
2个回答

7
你可以尝试以下方法。在Parent表中,创建一个冗余的UNIQUE约束条件,它包含(id, aId)这两个字段(SQL真是够蠢的!)。
CREATE TABLE Child
(parentId INTEGER NOT NULL,
 aId INTEGER NOT NULL UNIQUE,
FOREIGN KEY (parentId,aId) REFERENCES Parent (id,aId),
createdOn TIMESTAMP NOT NULL);

也许更好的解决方案是完全从 Child 表中删除 parentId,添加 bId 并基于 (aId, bId) 引用 Parent 表:
CREATE TABLE Child
(aId INTEGER NOT NULL UNIQUE,
 bId INTEGER NOT NULL,
FOREIGN KEY (aId,bId) REFERENCES Parent (aId,bId),
createdOn TIMESTAMP NOT NULL);

你为什么不能这样做呢?


我喜欢第二种方法。不需要触发器,表已经规范化了。(aId,bId) 也可以用作 ChildPRIMARY KEY - ypercubeᵀᴹ
抱歉,我的意思是 aId 可以用作 ChildPRIMARY KEY - ypercubeᵀᴹ

1
正确的方法是完全取消Child表,将createdOn列放在Parent表中,而不使用NOT NULL约束。你所说的只是一个Parent条目可以具有零个或一个(但不多于一个)createdOn值。你不需要一个单独的表。它不容易或明显的事实部分证明了我的观点。;-) SQL通常就是这样工作的。

但这并不能保证aId的唯一性。父表中的关键字是(aId, bId),而不是aId。 - nvogel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接