Разрешить/требовать только одной записи с общим FK, чтобы иметь «основной» флаг

StackOverflow https://stackoverflow.com/questions/9326606

  •  27-10-2019
  •  | 
  •  

Вопрос

Во -первых, я прошу прощения, если это обманывает - я подозреваю, что это может быть, но я не могу его найти.

Скажем, у меня есть таблица компаний:

 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. Анкет Или даже лучше, можно было бы построить триггер, чтобы запрос удастся, но TomS. is_primary Флаг будет очищен по той же операции?

Я не слишком беспокоюсь о том, company_id существует в companies Таблица, мой PHP -код уже выполнил бы эту проверку до того, как я добрался до этой стадии (хотя, если есть способ сделать это в той же операции, я полагаю, было бы хорошо).

Когда я изначально подумал об этом, я подумал: «Это будет легко, я просто добавлю уникальный индекс через company_id а также is_primary столбцы "Но, очевидно, это не сработает, так как это ограничило бы меня одним первичным и одним неприемным контактом - любая попытка добавить третий контакт потерпит неудачу. Но я не могу почувствовать, что будет способ настроить уникальный Индекс, который дает мне минимальную функциональность, которая мне требуется, - отклонить попытку добавить второй первичный контакт или отклонить попытку оставить компанию без основного контакта.

Я знаю, что могу просто добавить primary_contact поле к companies стол с FK в contacts Стол, но это кажется грязным. Мне не нравится идея о том, что обе таблицы имеют FK для другой - мне кажется, что один стол должен полагаться на другую, а не обе таблицы полагаются друг на друга. Думаю, я просто думаю, что со временем есть больше шансов, что что -то пойдет не так.

Подводить итоги:

  • Как я могу ограничить таблицу контактов так, чтобы одна и только одна запись с данной company_id имеет is_primary набор флага?
  • У кого -нибудь есть какие -либо мысли о том, является ли два таблица, имеющие FK друг с другом хорошей/плохой идеей?
Это было полезно?

Решение

Круговые рефенции между таблицами действительно грязные. Смотрите это (десятилетие) статья: SQL по дизайну: круговая ссылка

Самый чистый способ сделать такое ограничение - добавить другую таблицу:

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)

Другие советы

Вы могли бы просто сделать запрос перед этим настройкой

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, хотя вместо этого типа обходного пути, т.е.

РЕДАКТИРОВАТЬ Метод без полагаться на контакт.

Альтернативный метод, прежде всего, удалить is_primary из контактов. Во -вторых, добавьте в компании поле «promiser_contact_id» в компании. В -третьих, при изменении первичного контакта просто измените то, что primary_contact_id, таким образом, предотвращая возможность того, что в любое время существует более 1 первичного контакта, и без необходимости триггеров и т. Д. На заднем плане.

Этот вариант будет работать нормально в любом двигателе, поскольку он просто обновляет поле int, любая зависимость от FK и т. Д. Можно добавить/удалить по мере необходимости, но в простом его просто

Этот вариант жизнеспособен, если вам нужна одна из них, и именно одна ссылка от компаний на контакты, отмечающие первичные

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top