Во-первых, прошу прощения, если это обман - я подозреваю, что это может быть, но я не могу его найти.Разрешить/потребовать только одну запись с общим FK, чтобы иметь флаг «primary»
Скажем, у меня есть таблица компаний:
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
... запрос потерпит неудачу, потому что Tom
(id = 1
) уже попадает в качестве первичного контакта для company_id = 1
. Или даже лучше, можно ли построить триггер так, чтобы запрос был успешным, но флаг is_primary
будет очищен той же операцией?
Я не слишком беспокоюсь о том, что существует company_id
в таблице companies
, мой PHP-код уже выполнил бы эту проверку до того, как я доберусь до этой стадии (хотя, если есть способ сделать это в той же операции, быть красивым, я полагаю).
Когда я изначально думал об этом, я подумал: «Это будет легко, я просто добавлю уникальный индекс по столбцам company_id
и is_primary
», но, очевидно, это не сработает, поскольку это ограничит меня одним основным и одним не первичный контакт - любая попытка добавить третьего контакта не удалась. Но я не могу не чувствовать, что будет способ настроить уникальный индекс, который даст мне минимальную функциональность, требующую - отклонить попытку добавить второй первичный контакт или отказаться от попытки покинуть компанию без основного контакта.
Я знаю, что я мог бы просто добавить поле primary_contact
в таблицу companies
с FK на таблицу contacts
, но она кажется беспорядочной. Мне не нравится идея того, что обе таблицы имеют FK для другого - мне кажется, что одна таблица должна опираться на другую, а не на обе таблицы, полагающиеся друг на друга. Думаю, я просто думаю, что со временем больше шансов на то, что что-то пойдет не так.
Подводя итог:
- Как я могу ограничить таблицу контактов, так что одна и только одна запись с данной
company_id
установилis_primary
флаг? - У кого-нибудь есть мысли о том, являются ли две таблицы, имеющие FK друг для друга, хорошей/плохой идеей?
Я бы взял здесь взаимный подход FK. Очевидно, что вы не можете сделать оба этих «NOT NULL», так как тогда у вас есть проблема с курицей и яйцом, но при условии, что значение «primary_contact» с нулевым значением может быть решено, а также точно моделирует вашу существующую ситуацию (не может быть первичного контакта для компании). Не согласитесь, что это кажется грязным - если есть отношение 1 к (0 или 1), как здесь, это совершенно естественно. – Jon
@Jon Извините, может быть, я был недостаточно ясен, мне нужно избегать первичного контакта «NULL», поскольку он закручивает один из моих запросов. У меня есть запрос, чтобы перечислить все компании на одной странице, и как часть этого Я присоединяюсь к контактам на contacts.company_id = company.id' и имеет 'where contacts.is_primary = 1'. Таким образом, нет первичного контакта, я не беру отчет о компании, и если есть более того, я получаю больше одного. На самом деле я не беспокоился о том, чтобы ограничение было основано на обеих таблицах, я просто хочу, чтобы таблица контактов проверяла, что одна запись контакта всегда установлена на первичную. – DaveRandom
Циркулярные ссылки между таблицами, по крайней мере, грязные. –