在 1-to-n 数据库关系中存储首选条目

storing preferred entry in a 1-to-n database relation

我正在研究如何(最好)为关系数据库建模,以便它可以标记 1:n 关系中的(0 或 1)个条目是首选。

(实际上是要在mariadb 10.2中实现,不过应该没那么重要)

为简单起见,假设我有两个 table:

parent:

child:

问题是我需要建模一种方法来存储首选 child

我看到了两种方式,但我都不太喜欢:

  1. 在 parent 中添加一个字段,列出首选 child 的 ID,并将其设为 child.
  2. 的 FK
  3. 在 child 中添加一个布尔列以指示行是首选 child。

我看到的东西:

只有 1 个首选 child:

-> 这将我推向解决方案 1

可维护性

解决方案 1 在 table 和 parent 和 child 之间的两个方向上创建 FK。我不确定这样的结构如何能够持续到例如。一个 backup/restore 循环(如果需要的话),因为没有更多的顺序来创建 tables,它们需要在没有 FKs 的情况下创建,然后需要在以后添加。即使这些都被工具覆盖了,我仍然很担心长期的可维护性。

-> 这将我推向解决方案 2

因此,在我们选择一个解决方案之前,我不认为这两个解决方案都不是一个好的解决方案,有人可以考虑其他解决方案吗?

还有什么我忽略的要考虑的吗?

我不确定如何考虑规范化。

编辑:

输入后进一步挖掘,我想到了第三个似乎更优越的选项:添加第三个 table 来模拟首选 child。

本质上:

首选child:

都带有 FK,例如
外键 (parentid, childid) 引用 child (parentid, id)

可能还有一些更独特的键来确保它都是唯一的,但这解决了我上面的解决方案 1 中的 chicken-egg 并避免了应用程序可能在解决方案 2 中造成的混乱。

对于第三个选项,我做了一个快速的 fiddle:http://sqlfiddle.com/#!9/af77bf/5/0

我会选择选项 (2)。

在 PostgreSQL,AFAIK 中,没有 partial UNIQUE constraint,但有 partial UNIQUE index,可用于确保具有相同 parentId 的多行只有 1 preferred.

假设列 preferred 的类型为 boolean。您可以在列 parentid + preferred 上创建 partial UNIQUE index,其中 preferred 为真。

CREATE UNIQUE INDEX unique_parentid_preferred ON child (parentid, preferred) WHERE preferred is true;

添加具有相同 parentidpreferred = true 的行时抛出此错误:

ERROR:  duplicate key value violates unique constraint "unique_parentid_preferred" ...

选项 1 不错,但需要可空的首选 child_id 或临时禁用 FK 检查才能填充。尽管如此,在查询首选 child.

时,它仍然有效地使用了正常的 PK 和 FK 索引

选项 2 不是 IMO 的好解决方案,因为首选 child 标志会在行之间创建依赖关系。更新首选 child 需要更新多行,从而造成不一致的机会。它实际上可以在 MySQL / MariaDB 中以某种方式处理 - 如果您愿意将 NULL 用于 FALSE,(parent_id, is_preferred) 上的唯一索引将只允许一行 is_preferred = TRUE,并且is_preferred = NULL 的任意行数。但是你必须处理 NULL,这会增加一点复杂性,并且存在 non-NULL non-TRUE 值的风险。

选项 3 不错。它很简单,避免了使其他选项复杂化的问题,同时只要您将 PK / FK 字段编入索引,就可以有效使用索引。