Firstly, I apologise if this is a dupe – I suspect it may be but I can’t find it.
Say I have a table of companies:
id | company_name
----+--------------
1 | Someone
2 | Someone else
…and a table of contacts:
id | company_id | contact_name | is_primary
----+------------+--------------+------------
1 | 1 | Tom | 1
2 | 2 | Dick | 1
3 | 1 | Harry | 0
4 | 1 | Bob | 0
Is it possible to set up the contacts table in such a way that it requires that one and only one record has the is_primary flag set for each common company_id?
So if I tried to do:
UPDATE contacts
SET is_primary = 1
WHERE id = 4
…the query would fail, because Tom (id = 1) is already flagged as the primary contact for company_id = 1. Or even better, would it be possible to construct a trigger so that the query would succeed, but Tom‘s is_primary flag would be cleared by the same operation?
I am not too bothered about checking whether company_id exists in the companies table, my PHP code would already have performed this check before I got to this stage (although if there is a way to do this in the same operation it would be nice, I suppose).
When I initially thought about this I thought “that will be easy, I’ll just add a unique index across the company_id and is_primary columns” but obviously that won’t work as it would restrict me to one primary and one non-primary contact – any attempt to add a third contact would fail. But I can’t help feeling there would be a way to configure a unique index that gives me the minimum functionality I require – to reject an attempt to add a second primary contact, or reject an attempt to leave a company with no primary contact.
I am aware that I could just add a primary_contact field to the companies table with an FK to the contacts table but it feels messy. I don’t like the idea of both tables having an FK to the other – it seems to me that the one table should rely on the other, not both tables relying on each other. I guess I just think that over time there is more chance of something going wrong.
To sum up:
- How can I restrict the contacts table so that one and only one record with a given
company_idhas theis_primaryflag set? - Anyone have any thoughts on whether two tables having FKs to each other is a good/bad idea?
Circular refenences between tables are indeed messy. See this (decade old) article: SQL By Design: The Circular Reference
The cleanest way to make such a constraint is to add another table:
This will also require a
UNIQUEconstraint in tableContacton(company_id, id)