【发布时间】:2013-10-22 12:35:49
【问题描述】:
假设我有一个 PostgreSQL 数据库,其中包含表 A、B 和 C,其中 A 和 B 通过联结表 C 具有多对多关系。这些表具有以下 SQL 定义:
CREATE TABLE A
(
id serial NOT NULL,
CONSTRAINT A_pkey PRIMARY KEY (id)
)
CREATE TABLE B
(
id serial NOT NULL,
CONSTRAINT B_pkey PRIMARY KEY (id)
)
CREATE TABLE C
(
A_id integer NOT NULL,
B_id integer NOT NULL,
CONSTRAINT C_pk PRIMARY KEY (A_id, B_id),
CONSTRAINT A_fk FOREIGN KEY (A_id)
REFERENCES A(id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT B_fk FOREIGN KEY (B_id)
REFERENCES B(id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
现在我想确保每个 A 实例至少有一个 B 实例(换句话说:A 中的每个 id 至少作为 C 中的 A_id 出现一次)。是否可以使用数据库约束检查此属性?
【问题讨论】:
-
您是否尝试过创建一个从
A.id到C.A_id的延迟外键? -
是的,我想过。但是外键应该唯一地标识另一个表中的一行。在这种情况下,通常会有多个 C.A_id 与 A.id 值匹配,因此它不会是唯一的。我不确定这种方法是否仍然有效,但对我来说听起来有点脏。
-
最通用的解决方案是向表 A 和 B 添加引用计数;它将允许您对 C 表中的引用数量设置 any 限制。但它需要 C 表上的触发器函数来维护 A 和 B 表中的计数。顺便说一句,我认为没有触发器的解决方案是不可能的。 OTOH:在 {A,B} 表中有 orphan 行是个大问题,是否有合理的理由禁止它们? (没有工人的项目,没有项目的工人对我来说似乎很好,至少暂时是这样。比发明虚拟的 C 行来捕捉空闲的行要好)
-
这种类型的“至少 N”包含依赖在大多数 SQL DBMS 的声明性代码中几乎是不可能维护的。一次只能更新一个表,这或多或少是 SQL 模型的一个限制。常见的解决方法是在程序代码(例如触发器)中强制执行规则,在外部规则引擎中强制执行,或者干脆不强制执行。
-
要添加到@sqlvogel 出色的评论,您还可以创建一个后台作业,可能通过存储过程来查找违反规则的情况,并在出现问题时通知您。这不如实时管理好,但它会提醒您注意无意中导致此问题的代码更改..
标签: sql database postgresql database-design constraints