首先,如果这是一个骗局我道歉 – 我怀疑它可能是但我找不到它.
说我有一张公司表:
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
是否可以以这样的方式设置联系人表:它要求只有一条记录为每个公共company_id设置了is_primary标志?
所以如果我试图这样做:
UPDATE contacts
SET is_primary = 1
WHERE id = 4
…查询将失败,因为Tom(id = 1)已被标记为company_id = 1的主要联系人.或者甚至更好,是否可以构造一个触发器以使查询成功,但是Tom的is_primary标志会被同样的操作清除吗?
我不太关心检查company_id是否存在于公司表中,我的PHP代码在我进入这个阶段之前就已经执行了这个检查(虽然如果有一种方法可以在同一个操作中执行此操作,那将是很好的,我假设).
当我最初想到这一点时,我认为“这将很容易,我只会在company_id和is_primary列中添加一个唯一索引”,但显然这不会起作用,因为它会限制我只有一个主要联系人和一个非主要联系人 – 任何添加第三次联系的尝试都将失败.但我不禁觉得有一种方法可以配置一个独特的索引,它为我提供了我所需的最低功能 – 拒绝尝试添加第二个主要联系人,或拒绝尝试离开没有主要联系人的公司.
我知道我可以将一个primary_contact字段添加到Companies表中,并将FK添加到contacts表中,但它感觉很麻烦.我不喜欢两个表都有FK到另一个表的想法 – 在我看来,一个表应该依赖于另一个表,而不是两个表依赖于彼此.我想我只是觉得随着时间的推移出现问题的可能性会更大.
总结一下:
>如何限制联系人表,以便只有一个给定company_id的记录设置了is_primary标志?
>任何人都有任何关于两张桌子相互之间的FK是一个好/坏主意的想法吗?
解决方法:
表之间的循环反应确实很混乱.看到这个(十年之久)文章: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 on(company_id,id)