将首选条目存储在1对n数据库关系中

时间:2018-03-04 03:01:57

标签: database-design foreign-keys database-normalization

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

(它实际上是在mariadb 10.2中实现的,但这并不重要)

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

父:

  • ID
  • 名称

子:

  • ID
  • 名称
  • parentid(FK - > parent(id))

问题是我需要建模一种存储首选孩子的方法

我看到两种方式,但我不喜欢这两种方式:

  1. 在父级中添加一个字段,列出首选孩子的ID,并将其作为孩子的FK。
  2. 在子项中添加一个布尔列,表示行是首选子项。
  3. 我看到的事情:

    只有一个喜欢的孩子:

    • 在解决方案1的情况下,我只能有最大值。一个喜欢的孩子(=好)

    • 如果是解决方案2,我需要依靠该应用程序,每个父母只生一个首选孩子(=坏)

    - >这促使我解决方案1 ​​

    可维护性

    解决方案1在父表和子表之间的两个方向上创建FK。我不相信这样的建筑可以持续如何如果需要备份/恢复周期,因为没有更多的顺序来创建表,它们需要在没有FK的情况下创建,然后需要稍后添加。即使这些都被工具所覆盖,我仍然非常害怕长期可维护性。

    - >这促使我解决方案2

    所以在我们选择一个解决方案之前,我都不相信它是一个好的解决方案,任何人都有其他解决方案需要考虑?

    我忽略了还有什么需要考虑的事情吗?

    我不确定如何在规范化方面考虑这一点。

    编辑:

    在输入后再进一步挖掘,我想出了第三个看起来更优越的选项:添加第三个表来模拟首选孩子。

    基本上:

    preferredchild:

    • parentId的
    • childID的

    全部使用诸如
    的FK FOREIGN KEY(parentid,childid)REFERENCES child(parentid,id)

    可能还有一些更独特的钥匙可以确保它们都是独一无二的,但这解决了上述解决方案1中的鸡蛋,并避免了应用程序在解决方案2中可能造成的混乱。

    在第三个选项中,我做了一个快速的小提琴:http://sqlfiddle.com/#!9/af77bf/5/0

2 个答案:

答案 0 :(得分:0)

我会选择(2)。

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

假设列preferred的类型为boolean。您可以在列partial UNIQUE index上创建parentid + preferred,其中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 :(得分:0)

选项1并不坏,但需要一个可以为空的首选child_id或临时禁用FK检查来填充。不过,在查询首选孩子时,它可以有效地使用正常的PK和FK索引。

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

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