У меня есть 3 таблицы - users
, teams
и team_members
. Последнее представляет собой карту многих ко многим от team(id)
до user(id)
(внешние ключи до teams
и users
соответственно). Есть ли какая-либо проверка целостности, которую я могу добавить в свою базу данных, которая может утверждать, что, хотя команды без участников могут быть, но пользователи без команд невозможно? Чтобы уточнить, я хочу обеспечить соблюдение на уровне базы данных, что все пользователи должны принадлежать к команде atleast 1 (при этом не требуется, чтобы все команды имели 1 пользователь). Ответ, который работает в MYSQL или Postgres, является приемлемым.Проверка целостности ссылочной целостности в SQL
ответ
(Ответ предполагает PostgreSQL;. Сведения о триггерах и блокировке будут меняться, если вы используете другой СУБД, но большинство RDBMSes должно быть в состоянии поддерживать те же основные операции)
Хотя можно добавить внешний ключ от users
до teams
, для этого требуется дублирование знаний - в основном вы создадите дополнительную связь m: 1 в дополнение к отношениям exisitng m: n. Это нежелательно.
Если вам не нужно много параллелизма, лучшим вариантом здесь, вероятно, является использование отложенных триггеров ограничений и блокировки таблиц. Добавить:
отложенное триггер ограничение
ON INSERT OR UPDATE ... FOR EACH ROW
триггер наusers
, что делаетLOCK TABLE users, team_members IN EXCLUSIVE MODE
, а затем проверяет, что созданный пользователем, если он не был удален, так как, по меньшей мере одну команду с помощью объединения черезteam_members
. Ваше приложение будет хотетьLOCK TABLE users IN EXCLUSIVE MODE
, прежде чем писать ему, а также для предотвращения взаимоблокировок. Обратите внимание, чтоEXCLUSIVE MODE
не предотвращаетSELECT
.a отложенный триггер ограничения
ON UPDATE OR DELETE ... FOR EACH ROW
наteam_members
, который делает то же самое в обратном порядке, убедившись, что если вы удалите членство в команде, то пользователь, который был членом, все еще имеет другие членства в команде. Он также должен блокировать какusers
, так иteam_members
.
Конечно, team_members
также нуждается FK ограничения на users
и teams
, но это должно быть просто считать для т: п присоединиться к таблице.
Если вы не против того, чтобы тщательно выполнять действия в определенных заказах, например. всегда добавляйте новое членство перед удалением старого, вы можете использовать обычный триггер вместо триггера отложенного ограничения. Это даст вам ошибки сразу после того, как вы сделаете что-то неправильно, а не во время COMMIT, но сделаете определенные упорядочения операторов, которые в противном случае были бы допустимыми в условиях ошибки.
Если вам нужен хороший параллелизм, вы, вероятно, набиты.
Если вам не нужны команды team_members, вы могли бы сделать это с помощью столбца массива для замены 'team_members', некоторых триггеров для подделки FK и CHECK, чтобы гарантировать, что массив не пуст? Условия гонки? –
@muistooshort Вы можете, но триггеры FK имеют некоторые специальные трюки, которые вы не можете легко эмулировать с помощью пользовательских триггеров. Расы были бы проблемой, как вы подозревали, если вы не сделали блокировки на уровне стола. В этом случае вы могли бы также провести традиционное реляционное моделирование. –
Ну, это исключает Mysql, поскольку у него нет отложенных ограничений. – pathikrit
Что вы используете? MySQL или Postgres? –
Я открыт для обоих. – pathikrit
Просто мысль. Ваше ограничение означает, что когда вы пытаетесь «ВСТАВИТЬ» строку в «пользователей», вы должны также «ВСТАВИТЬ» хотя бы одну строку в «team_members». Таким образом, вся операция не является атомарной, и проверка ограничения должна быть отложена до тех пор, пока обе таблицы не будут изменены. Он пахнет каким-то причудливым триггером. Было бы интересно увидеть решение. –