Из бизнес-правил, которые вы дали
- у каждого родителя должен быть хотя бы один ребенок,
- у каждого родителя должен быть один любимый ребенок,
- у каждого родителя может быть один наименее любимый ребенок
Ваше решение
Parent table:
parentId (PK)
favouriteChildId NOT NULL (FK)
leastFavouriteChildId NULL (FK)
Child table:
childId (PK)
parentId (FK)
удовлетворяет 2 и 3. Но также он удовлетворяет 1 (поскольку избранныйChildId NOT NULL не позволит создавать родительские записи без дочерних элементов).
Поскольку у вас уже есть вышеизложенное, я предполагаю, что реальный вопрос для вас заключается в том, как сделать parentId в дочерней таблице НЕ NULL.
Обычно в SQL есть возможность сделать что-то вроде
BEGIN TRANS
INSERT INTO TABLE1 (FK not checked yet)
INSERT INTO TABLE2 (FK not checked yet)
COMMIT (All integrity checked)
в этом случае «циклическая ссылка» не будет проблемой (см. DEFERRED а>)
Mysql не поддерживает его, поэтому у вас есть следующие варианты
Триггеры:
Можно предположить, что во время вставки родительской записи любимый дочерний элемент уже известен, тогда у вас может быть триггер, который будет запускаться перед вставкой в родительскую таблицу и
- вставьте любимый дочерний элемент в дочернюю таблицу, получив его идентификатор
- вставьте родительскую запись с идентификатором ребенка
ПРИМЕЧАНИЕ. Проблема в том, что таким образом вы можете формально удовлетворить критерии, но чтобы сначала вставить дочернюю запись, вам придется либо использовать дополнительные столбцы в родительской, чтобы триггер мог знать о других полях в дочерней таблице, либо вставить пустую запись (в в любом случае дизайн не чистый)
Целостность через безопасность
Вышеописанное можно реализовать в виде хранимой процедуры, не требуя дополнительных полей на уровне родительской таблицы. Однако хранимые процедуры обычно можно обойти, поэтому это не считается настоящим правилом целостности.
Существует общий способ сделать что-то, достигнутое с помощью хранимой процедуры, квалифицируемым как правило целостности, а именно удалить разрешения на запись для всех обычных пользователей (и приложений) для этих таблиц и разрешить изменение данных только через хранимую процедуру.
РЕДАКТИРОВАТЬ: Что касается триггеров, есть также способ реализовать правило с триггерами, и это означает, что вам придется вставлять записи отдельно и что вы можете иметь данные, которые в какой-то момент нарушают ваши бизнес-правила.
В этом случае вы можете иметь атрибут STATUS для родительской записи (например: COMPLETE vs INCOMPLETE) и сделать favouriteChildId FK, допускающим значение NULL, но при обновлении статуса на COMPLETE вы можете запустить проверку целостности.
Это требует дополнительного столбца, но может сделать вещи довольно чистыми (на самом деле вы можете создать представление для этой таблицы, которое будет отображать только записи, которые являются ЗАВЕРШЕННЫМИ, фактически делая его выглядящим как таблица с FK NOT NULL).
person
Unreason
schedule
16.05.2011