【问题标题】:Unique constraint over multiple tables对多个表的唯一约束
【发布时间】:2011-09-10 22:54:49
【问题描述】:

假设我们有这些表:

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 中的所有行最多引用一个Parent,其值为aId?换句话说,我可以创建一个唯一约束,以便上述表的连接不会有重复的aId?我认为不是——我能找到的每个数据库的语法似乎都与每个约束绑定到一个表——但这可能是我缺乏想象力。 (当然,去规范化以在 Child 上包含 aId 是一种解决方案。)

【问题讨论】:

  • 您可以在插入或更新时使用触发器来执行和响应您的约束逻辑,但我认为触发器应该是绝对的最后手段——我宁愿在业务层这样做。
  • 我同意 hamlin11 的观点,我不希望在业务层看到这一点,但在大多数情况下使用数据库触发器。
  • 业务层将是放置这种逻辑的最糟糕的宫殿,如果它对于约束来说太简单了,那么触发器是正确的方法。它当然必须是一个正确编写且性能良好的触发器(编写糟糕的触发器会导致触发器的表现不佳)。

标签: sql postgresql normalization denormalization relational-algebra


【解决方案1】:

您可以尝试以下方法。您必须在 Parent 中的 (id, aId) 上创建一个冗余的 UNIQUE 约束(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);

可能更好的解决方案是将 parentId 从 Child 表中完全删除,添加 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) 也可以用作PRIMARY KEYChild
  • 抱歉,我的意思是aId 可以用作PRIMARY KEYChild
【解决方案2】:

执行此操作的正确方法是完全取消Child 表并将createdOn 列放入Parent 表中,而不使用NOT NULL 约束。您所说的是一个Parent 条目可以有零个或一个(但不能更多)createdOn 值。你不需要一个单独的表。这样做并不容易或不明显这一事实部分地证明了我的观点。 ;-) SQL 通常以这种方式运行。

【讨论】:

  • 但这不会强制 aId 的唯一性。父表中的键是 (aId, bId) 而不是 aId。
猜你喜欢
  • 2012-05-07
  • 2010-12-22
  • 1970-01-01
  • 2018-06-29
  • 2017-01-02
  • 1970-01-01
  • 2018-09-14
  • 1970-01-01
  • 2013-04-30
相关资源
最近更新 更多