Может ли внешний ключ быть нулевым?
В нашем проекте базы данных у нас есть таблица Sale
который имеет первичный ключ и два эксклюзивных внешних ключа: Vehicle_ID
а также Piece_ID
, Например, если мы продаем автомобиль, нам нужно Vehicle_ID
в качестве внешнего ключа, но не Piece_ID
, Можем ли мы поставить NULL Piece_ID
может ли внешний ключ быть нулевым? Или есть способ сделать эту работу?
Благодарю.
4 ответа
Столбец (или столбцы) первичного ключа должен иметь значение NOT NULL. Запись не может быть однозначно идентифицирована как NULL. Таким образом, столбцы идентификаторов на указанном конце внешнего ключа должны быть определены как NOT NULL.
Тем не менее, это законное проектное решение, чтобы отношение внешнего ключа было необязательным, и способ представить это - сделать необязательным конец ссылки на ключ, то есть разрешить NULL.
В терминах моделирования данных вы описали (исключительную) дугу: "таблица... с двумя или более внешними ключами, где один и только один из них может быть ненулевым". В логическом моделировании дуги вполне приемлемы, но существует твердое мнение в пользу их использования в качестве отдельных таблиц. В вашем сценарии это будет общим Sale
таблица плюс две таблицы подтипов, VehicleSale
а также PieceSale
,
Преимущества реализации отдельной таблицы:
- легче применять ограничения внешнего ключа;
- проще добавить дополнительные столбцы, касающиеся, скажем, продаж автомобилей, которые не относятся к продажам штучных товаров;
- проще расширять модель дополнительными подтипами;
- Более четкая модель данных, которая может упростить разработку приложений.
Однако преимущества не являются односторонними. Хотя довольно легко убедиться, что Sale
относится либо к VehicleSale
или PieceSale
но не оба, соблюдение правила о том, что Sale
Должно быть, запись о ребенке на самом деле становится довольно мрачной.
Таким образом, преобладающий совет заключается в том, что исключительная дуга ошибочна, и, как правило, это хороший совет. Но это не так ясно, как некоторые видят.
Ответ:
Да, вы можете сделать это - сделать FK сами по себе NULL-совместимыми, но добавьте CHECK, чтобы убедиться, что ровно один из них содержит ненулевое значение.
Разработка:
FK может иметь значение NULL, что моделирует отношение 1..0:N. Другими словами, "дочерняя" строка может (но не обязана) иметь "родительскую" строку.
Внешний ключ NOT NULL моделирует отношение 1:N. Другими словами, у каждого ребенка должен быть родитель.
Когда FK является составным1, и по крайней мере одно из его полей поддерживает NULL, сочетание значений NULL и не-NULL обрабатывается особым образом:
- Если FK равен MATCH FULL, либо все значения должны быть NULL, либо все значения должны быть не NULL и соответствовать некоторой родительской строке.
- Если FK является MATCH PARTIAL, только те значения, которые не являются NULL, должны соответствовать некоторой родительской строке (NULL игнорируются).
- Если FK равен MATCH SIMPLE, либо все значения не равны NULL и должны совпадать с некоторой родительской строкой, либо имеется хотя бы одно значение NULL (в этом случае не-NULL совпадать не требуется).
Большинство СУБД по умолчанию соответствуют MATCH SIMPLE (за исключением MS Access), и большинство не поддерживают ничего, кроме значения по умолчанию.
1 Которого у вас здесь нет - просто упомяну это для полноты.
В зависимости от того, что вы подразумеваете под "эксклюзивными внешними ключами", вы можете думать о транспортных средствах и деталях как о двух подклассах какого-то более крупного суперкласса, называя это товарными товарами.
Если вы используете шаблон проектирования под названием "наследование таблиц классов", у вас будет три таблицы, одна для суперкласса и одна для каждой таблицы подкласса. Кроме того, если вы используете конструкцию, называемую "общий первичный ключ", вы можете использовать один и тот же первичный ключ для всех трех таблиц.
Это позволит вашей таблице Sale иметь единственный внешний ключ, Saleable_Item_Id, который ссылается на таблицу Saleable_Item, а также на таблицу Vehicle или Piece, в зависимости от случая. Это может сработать лучше, чем существующий дизайн.
Google "наследование таблицы классов" и "общий первичный ключ" для более подробной информации.
Oracle не должен жаловаться, если у вас нулевой внешний ключ.
Вы сталкивались с некоторыми ошибками?