我正在寻找如何(最好)建模关系数据库,以便它可以标记1:n关系中的(0或1)条目是首选。
(它实际上是在mariadb 10.2中实现的,但这并不重要)
为简单起见,假设我有两个表:
父:
子:
问题是我需要建模一种存储首选孩子的方法
我看到两种方式,但我不喜欢这两种方式:
我看到的事情:
只有一个喜欢的孩子:
在解决方案1的情况下,我只能有最大值。一个喜欢的孩子(=好)
如果是解决方案2,我需要依靠该应用程序,每个父母只生一个首选孩子(=坏)
- >这促使我解决方案1
可维护性
解决方案1在父表和子表之间的两个方向上创建FK。我不相信这样的建筑可以持续如何如果需要备份/恢复周期,因为没有更多的顺序来创建表,它们需要在没有FK的情况下创建,然后需要稍后添加。即使这些都被工具所覆盖,我仍然非常害怕长期可维护性。
- >这促使我解决方案2
所以在我们选择一个解决方案之前,我都不相信它是一个好的解决方案,任何人都有其他解决方案需要考虑?
我忽略了还有什么需要考虑的事情吗?
我不确定如何在规范化方面考虑这一点。
编辑:
在输入后再进一步挖掘,我想出了第三个看起来更优越的选项:添加第三个表来模拟首选孩子。
基本上:
preferredchild:
全部使用诸如
的FK
FOREIGN KEY(parentid,childid)REFERENCES child(parentid,id)
可能还有一些更独特的钥匙可以确保它们都是独一无二的,但这解决了上述解决方案1中的鸡蛋,并避免了应用程序在解决方案2中可能造成的混乱。
在第三个选项中,我做了一个快速的小提琴:http://sqlfiddle.com/#!9/af77bf/5/0
答案 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;
当添加了具有相同parentid
和preferred = 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字段编入索引,就可以保留索引的有效使用。