Sql server 每个组中仅一条标记为主记录的约束

Sql server 每个组中仅一条标记为主记录的约束,sql-server,constraints,Sql Server,Constraints,我如何在表上设置一个约束来强制每个组只有一条记录被标记为“主记录” 例如,在提供高风险惊险运动的公司的数据库中,他们有table Customer和table EmergencyContact,其中从EmergencyContact到Customer存在FK约束。对于每个客户记录,可能有零个或多个紧急联系人记录。如果客户有一个或多个紧急联系人,则其中一个必须标记为主要联系人。如果只有一个紧急联系人,那显然就是必须标记为主要联系人的联系人 请注意,相关约束很容易实现,并且可能是解决方案的一部分-强

我如何在表上设置一个约束来强制每个组只有一条记录被标记为“主记录”

例如,在提供高风险惊险运动的公司的数据库中,他们有table Customer和table EmergencyContact,其中从EmergencyContact到Customer存在FK约束。对于每个客户记录,可能有零个或多个紧急联系人记录。如果客户有一个或多个紧急联系人,则其中一个必须标记为主要联系人。如果只有一个紧急联系人,那显然就是必须标记为主要联系人的联系人

请注意,相关约束很容易实现,并且可能是解决方案的一部分-强制每个客户不超过一个紧急联系人被标记为主要联系人。在stackoverflow上已经有很多这样的问题(和很好的答案),例如,等等。但是,我还没有找到一个答案(或任何其他方法)来强制每个组至少标记一个子记录,如果存在任何子记录

如果可能,我希望避免在计算列中使用触发器或基于UDF的约束。触发器可能会被禁用,并且不会总是触发(参见亚历克斯·库兹涅佐夫的优秀著作第208页),在某些情况下,包含在检查约束中的自定义项也可能被绕过或忽略(参见本书第184页之后)


我尝试了几种方法来解决这个问题,例如索引视图以及父表到子表的FK约束,但都没有成功。

我个人处理这个问题的方法是使用检查约束

如果必须避免检查约束和触发器,则下一个最佳选项是设置表的权限,以便拒绝临时插入和更新,并且更改表中数据的唯一方法是通过存储过程。然后将您描述的逻辑放入存储过程代码中


您无法找到使用索引或外键执行此操作的方法。

注意,只有具有ALTER TABLE权限的用户才能绕过触发器执行,这样的用户还可以禁用外键和检查约束,重新启用它们检查现有行,并禁用索引。@DavidBrowne Microsoft-强制执行约束的触发器(如此处所示)除非采取特殊预防措施,否则在使用快照事务隔离级别时也可能失败。(即使如此,我也不确定他们是否100%可靠)。绝对同意。编写总是按照您的意愿执行并且不引入性能问题或死锁的触发器是很棘手的。在某种程度上,放弃让数据库强制执行特定的业务规则通常比使用触发器强制执行要好。@DavidBrowne Microsoft触发器有时在快照隔离下运行时会失败。请参阅亚历克斯·库兹涅佐夫(Alex Kuznetsov)的优秀著作,从第114页开始,特别是第122页快照模式下的副标题触发行为。()引用SQL Server的防御性数据库编程:“我们是否可以开发出更健壮的触发器;那些在快照隔离下继续执行我们的业务规则的触发器?在这种情况下,我不这么认为。”