限制数据库级别的关联记录数

时间:2014-09-24 12:08:53

标签: mysql sql postgresql database-design foreign-keys

假设我有两个表parentschildren。父母自然会有很多孩子与一对多的关联。 MySQL或PostgreSQL中是否有任何构造允许限制关联对象的数量,如:

FOREIGN KEY (parent_id) 
  REFERENCES parent(id)
  LIMIT 3

这样的事情是否存在或我们是否需要自定义触发器?

1 个答案:

答案 0 :(得分:2)

不在外键的定义中。我会通过为每个父母添加一个序列号来解决这个问题(代码为 PostgreSQL ,主体是标准SQL):

CREATE TABLE child (
   child_id  serial PRIMARY KEY
 , parent_id int NOT NULL REFERENCES parent
 , child_nr  int NOT NULL
 , CHECK (child_nr BETWEEN 1 AND 3)
 , UNIQUE (parent_id, child_nr)
);

通过这种方式,您可以为每个父母提供1到3个孩子,或者为这些父母提供一些或不提供任但没有其他人。

由于您现在拥有(parent_id, child_nr)的自然PK,您可以删除代理PK列child_id。但我喜欢几乎每张桌子都有一个单列代理PK ......

可以使用触发器来限制数量,该数字会在插入新的儿童之前检查已有多少儿童。但是你会遇到并发问题,而且它更昂贵,更不可靠,更容易规避和特定于供应商。

如何管理child_nr

RDBMS只强制(可靠地)表中不存在非法状态。你如何找出下一个child_nr取决于你。许多不同的方法都是可能的。

对于三个孩子,可以在创建父项时自动插入所有子项(使用触发器,规则或在应用程序中)。给定(parent_id, child_nr)和其他列NULL。

然后,您只允许UPDATE而不是INSERTDELETE用于子表(GRANT / REVOKE),甚至可以确保使用其他人触发器,以便超级用户无法绕过它。使用parent将FK设为ON DELETE CASCADE,这样孩子就会自动死于父母。

替代

可靠性稍差但更便宜:在parent表中保留一定数量的儿童,并将其限制为<= 3。使用触发器对child表中的每个更改进行更新。请务必涵盖更改子表中数据的所有可能方法。