【问题标题】:Limit number of associated records on DB level限制数据库级别的关联记录数
【发布时间】:2014-11-18 22:13:07
【问题描述】:

假设我有两个表parentschildren。自然地,父母可能有许多具有一对多关联的孩子。 MySQL 或 PostgreSQL 中是否有任何结构可以限制关联对象的数量,例如:

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

是否存在类似的东西,或者我们是否需要自定义触发器?

【问题讨论】:

  • 我认为您需要为 MySQL 自定义触发器。我不知道有这样的功能。
  • @VMai 是正确的,没有像它这样的功能。您必须使用自定义触发器来实现它。

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


【解决方案1】:

不在外键的定义中。我会通过像这样为每个父母的每个孩子添加一个序列号来解决这个问题(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。

那么对于子表(GRANT/REVOKE),您将只允许UPDATE 而不允许INSERTDELETE,或者甚至确保使用另一个触发器,以便超级用户无法绕过它。使用ON DELETE CASCADE 将FK 设置为parent,这样孩子就会自动与父母一起死去。

另类

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

【讨论】:

  • 我喜欢这个主意!几个问题 - 如何处理child_nr 列?我认为它需要在应用程序级别?
  • @BroiSatse:RDBMS 只是强制(可靠地)您不能插入任何非法内容。如何确定下一个 child_nr 取决于您。我添加了一项建议。
  • 非常感谢,很棒的答案。我想我会围绕您发布的替代方案进行更多研究。我是 rails 开发人员,并且已经有一个功能可以处理这个额外的计数器列 - 不过需要检查它在 db 级别上的可靠性。再次 - 非常感谢。
  • @BroiSatse:值得一提的是,由于缺乏检查约束,这种方法不适用于 MySQL。
猜你喜欢
  • 2014-01-13
  • 1970-01-01
  • 2016-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多