允许/仅需要一个具有公共FK的记录具有“主”标志

时间:2012-02-17 10:29:57

标签: mysql triggers unique-index

首先,如果这是一个骗局我道歉 - 我怀疑它可能是但我找不到它。

说我有一张公司表:

 id | company_name
----+--------------
  1 | Someone
  2 | Someone else

......还有一个联系人表:

 id | company_id | contact_name | is_primary
----+------------+--------------+------------
  1 |     1      | Tom          |      1
  2 |     2      | Dick         |      1
  3 |     1      | Harry        |      0
  4 |     1      | Bob          |      0

是否可以以要求的方式设置contacts表,只有一条记录为每个公共is_primary标记设置company_id标记UPDATE contacts SET is_primary = 1 WHERE id = 4 1}}?

所以,如果我试图这样做:

Tom

...查询将失败,因为id = 1company_id = 1)已被标记为Tom的主要联系人。或者甚至更好,是否可以构造一个触发器以使查询成功,但is_primary的{​​{1}}标志将被同一操作清除?

我不太关心检查company_id表中是否存在companies,我的PHP代码在进入此阶段之前已经执行了此检查(尽管有办法在同样的操作中,我认为这很好。

当我最初考虑这个问题时,我认为“这很简单,我只会在company_idis_primary列中添加一个唯一索引”,但显然这样做不会有效将我限制为一个主要联系人和一个非主要联系人 - 任何添加第三个联系人的尝试都将失败。但我不禁觉得有一种方法可以配置一个独特的索引,它为我提供了我所需的最低功能 - 拒绝尝试添加第二个主要联系人,或拒绝尝试离开没有主要联系人的公司。

我知道我可以在primary_contact表中添加companies字段,并将{FK}添加到contacts表,但感觉很麻烦。我不喜欢两个表都有FK到另一个表的想法 - 在我看来,一个表应该依赖于另一个表,而不是两个表依赖于彼此。我想我只是认为随着时间的推移,出现问题的可能性会更大。

总结一下:

  • 如何限制联系人表格,以便只有一条给定company_id的记录设置了is_primary标记?
  • 任何人都不知道两张桌子之间是否存在FK是好事还是坏事?

2 个答案:

答案 0 :(得分:3)

表之间的循环反应确实很混乱。见这篇(十年前的)文章:SQL By Design: The Circular Reference

制定此类约束的最简洁方法是添加另一个表:

Company_PrimaryContact
----------------------
company_id
contact_id
PRIMARY KEY (company_id)
FOREIGN KEY (company_id, contact_id)
  REFERENCES Contact (company_id, id)

这还需要在UNIQUE

上的表Contact中设置(company_id, id)约束

答案 1 :(得分:2)

您可以在该设置之前进行查询

UPDATE contacts SET is_primary = 0 WHERE company_id = .....

甚至

UPDATE contacts
SET is_primary = IF(id=[USERID],1,0)
WHERE company_id = (
    SELECT company_id FROM contacts WHERE id = [USERID]
);

只是在那里添加一个替代方案 - 我个人可能会考虑FK方法,而不是这种类型的解决方法,即在公司表中有一个带有primary_user_id字段的字段。

编辑方法,不依赖于contact.is_primary字段

替代方法,首先从联系人中删除is_primary。其次,在公司中添加“primary_contact_id”INT字段。第三,在更改主要联系人时,只需更改该primary_contact_id,从而防止任何时候有任何超过1个主要联系人的可能性,并且在后台不需要触发器等。

这个选项可以在任何引擎中正常工作,因为它只是更新INT字段,可以根据需要添加/删除对FK等的任何依赖,但最简单的是它只是更改INT字段值

只要您需要一个从公司到标记主要

的联系人的链接,此选项就可行