Может ли внешний ключ быть пустым и / или дублированным?

325

Пожалуйста, уточните две вещи для меня:

  1. Может ли внешний ключ быть пустым?
  2. Может ли внешний ключ быть дублированным?

Насколько я знаю, NULLего нельзя использовать во внешних ключах, но в некоторых моих приложениях я могу вводить данные NULLкак в Oracle, так и в SQL Server, и не знаю почему.

джемы
источник
1
@Adrian: Насколько мне известно, внешний ключ не может быть нулевым, но он принимает значение null в SQL Server и Oracle. можешь объяснить почему?
джемы
@Jams - прочитайте ссылку в моем ответе.
JNK
11
это не может быть удалено, потому что ответы и вопрос полезны. Не стесняйтесь редактировать вопрос, чтобы улучшить его.
Джефф Этвуд
Пожалуйста, отделите вопрос о дубликатах. Только тот, о NULL, ответили ниже.
reinierpost

Ответы:

529

Краткий ответ: Да, это может быть NULL или дубликат.

Я хочу объяснить, почему внешний ключ может быть нулевым или уникальным или не уникальным. Во-первых, помните, что внешний ключ просто требует, чтобы значение в этом поле сначала существовало в другой таблице (родительской таблице). Это все ФК по определению. Ноль по определению не является значением. Нуль означает, что мы еще не знаем, какова стоимость.

Позвольте мне привести пример из жизни. Предположим, у вас есть база данных, в которой хранятся коммерческие предложения. Предположим далее, что каждому предложению назначен только один продавец и один клиент. Таким образом, ваша таблица предложений будет иметь два внешних ключа, один с идентификатором клиента и один с идентификатором торгового представителя. Однако во время создания записи торговый представитель не всегда назначается (поскольку никто еще не может работать над ней), поэтому идентификатор клиента заполнен, но идентификатор торгового представителя может быть нулевым. Другими словами, обычно вам нужна возможность иметь нулевой FK, когда вы можете не знать его значение во время ввода данных, но вы знаете другие значения в таблице, которые необходимо ввести. Чтобы разрешить нулевые значения в FK, как правило, все, что вам нужно сделать, это разрешить нулевые значения в поле, в котором есть FK. Нулевое значение отличается от идеи, что это FK.

Является ли он уникальным или не уникальным, зависит от того, имеет ли таблица отношение «один-один» или «один-много» к родительской таблице. Теперь, если у вас есть отношение один к одному, возможно, что вы могли бы хранить все данные в одной таблице, но если таблица становится слишком широкой или если данные по другой теме (сотрудник - пример страхования @tbone дал например), то вы хотите отдельные таблицы с FK. Затем вы захотите сделать этот FK либо PK (который гарантирует уникальность), либо наложить на него уникальное ограничение.

Большинство FK предназначены для отношений один-ко-многим, и это то, что вы получаете от FK без добавления дополнительных ограничений на поле. Таким образом, у вас есть таблица заказа и таблица деталей заказа, например. Если клиент заказывает десять товаров за один раз, у него есть один заказ и десять подробных записей заказа, которые содержат тот же идентификатор заказа, что и FK.

HLGEM
источник
13
Так это должно быть лучше, чем иметь поддельного продавца по имени "Неназначенный"?
Томас Уэллер
8
Комментарий. Нули оставляют много места для ошибок в запросе людьми, которые не знают, как SQL (неправильно) обрабатывает 3VL. Если продавец действительно не нужен для определенной таблицы, просто не включайте эту запись. Отдельная таблица может быть «ProposalAssignedTo» или чем-то подобным, с соответствующими ограничениями. Затем автор запросов может присоединиться к этой таблице и предоставить собственную логику для всего, что мы хотим сделать, когда в предложении нет продавца. NULL не просто означает «мы не знаем» - его можно использовать для многих вещей (вот почему это почти всегда плохая идея)
N West
26
@nWest, я не позволяю людям, которые некомпетентны запрашивать мои базы данных, и любой разработчик, который не знает, как обрабатывать нули, некомпетентен. Есть моменты, когда данные не известны во время начального ввода данных для определенного поля, но другие поля необходимы в это время.
HLGEM
28
@ThomasWeller Ссылка на фальшивого продавца («Неназначенный») усугубляет проблему. Я предполагаю, что ваша таблица продавца имеет несколько столбцов ...? Какой номер социального страхования мистера Unassigned? На какой отдел он назначен? Кто его босс? Я надеюсь, что вы поняли мою точку зрения: когда вы создаете «неназначенного» продавца, вы быстро обнаруживаете, что вы торговали NULLв одной таблице за несколько NULLединиц в другой таблице.
Гили
1
@ThomasWeller У вас также будет проблема, если / когда вам нужно будет локализовать ваш интерфейс.
Тобив
45

Изо рта лошади:

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

Нет ограничений на внешний ключ

Когда никакие другие ограничения не определены для внешнего ключа, любое количество строк в дочерней таблице может ссылаться на одно и то же значение родительского ключа. Эта модель допускает пустые значения во внешнем ключе. ...

NOT NULL ограничение на внешний ключ

Когда пустые значения не допускаются во внешнем ключе, каждая строка в дочерней таблице должна явно ссылаться на значение в родительском ключе, поскольку нулевые значения не допускаются во внешнем ключе.

Любое количество строк в дочерней таблице может ссылаться на одно и то же значение родительского ключа, поэтому эта модель устанавливает отношение один-ко-многим между родительским и внешним ключами. Однако каждая строка в дочерней таблице должна иметь ссылку на значение родительского ключа; отсутствие значения (ноль) во внешнем ключе не допускается. Тот же пример в предыдущем разделе можно использовать для иллюстрации таких отношений. Однако в этом случае сотрудники должны иметь ссылку на конкретный отдел.

УНИКАЛЬНОЕ ограничение на внешний ключ

Когда ограничение UNIQUE определено для внешнего ключа, только одна строка в дочерней таблице может ссылаться на заданное значение родительского ключа. Эта модель допускает пустые значения во внешнем ключе.

Эта модель устанавливает взаимно-однозначное отношение между родительским и внешним ключами, которое допускает неопределенные значения (нули) во внешнем ключе. Например, предположим, что в таблице сотрудников есть столбец с именем MEMBERNO, который ссылается на номер участника сотрудника в плане страхования компании. Кроме того, таблица INSURANCE имеет первичный ключ с именем MEMBERNO, а другие столбцы таблицы содержат соответствующую информацию, касающуюся страхового полиса сотрудника. MEMBERNO в таблице сотрудников должен быть как внешним ключом, так и уникальным ключом:

  • Для обеспечения соблюдения правил ссылочной целостности между таблицами EMP_TAB и INSURANCE (ограничение FOREIGN KEY)

  • Чтобы гарантировать, что каждый сотрудник имеет уникальный номер участника (ограничение UNIQUE)

УНИКАЛЬНЫЕ и НЕ НУЛЬНЫЕ ограничения на внешний ключ

Если для внешнего ключа определены ограничения UNIQUE и NOT NULL, только одна строка в дочерней таблице может ссылаться на заданное значение родительского ключа, а поскольку значения NULL не допускаются во внешнем ключе, каждая строка в дочерней таблице должна явно ссылаться значение в родительском ключе.

Посмотри это:

Oracle 11g ссылка

TBone
источник
16

Да, внешний ключ может быть нулевым, как сказано выше старшими программистами ... Я бы добавил еще один сценарий, когда внешний ключ должен быть нулевым .... предположим, у нас есть таблицы комментариев, изображений и видео в приложении, которое позволяет комментировать изображения и ролики. В таблице комментариев мы можем иметь два ForeignIs PicturesId и VideosId вместе с первичным Key CommentId. Поэтому, когда вы комментируете видео, потребуется только VideosId, а pictureId будет нулевым ... и если вы прокомментируете только изображение, потребуется PictureId, а VideosId будет нулевым ...

Тусиф Ахмед Аван
источник
1
Я думаю, что есть лучший способ решить эту проблему. Вместо создания новых столбцов у вас может быть два столбца, а именно «id» и «type», которые будут содержать идентификатор и имя таблицы внешнего ключа. Например, id = 1, type = Picture будет представлять ссылку на таблицу изображений с идентификатором 1. Преимущество использования этого решения заключается в том, что вам не нужно создавать новые столбцы, когда комментарии добавляются в дополнительные таблицы. Недостатком будет отсутствие ограничения внешнего ключа на уровне базы данных, скорее ограничение должно быть на уровне приложения.
Agent47DarkSoul
4
@Agent: у нас было это «решение» в производстве. Не делай этого, это ужасно. Создание запросов превращается в беспорядок: «если это тип 1, присоединяйтесь к этой таблице, в противном случае присоединяйтесь к этой». Это был кошмар для нас. В итоге мы сделали то, что говорит этот ответ, и создали новый столбец для каждого типа объединения. Создание столбцов это дешево. В значительной степени недостатком является то, что большое количество столбцов затрудняет использование Toad, но это всего лишь недостаток Toad.
user128216
1
@FighterJet Rails предоставляет отличную среду ORM, которая обрабатывает даже сложные запросы с этим решением.
Agent47DarkSoul
2
@ Агент: Может быть, это может ... но если вы можете сделать это просто, зачем делать это сложным? И, возможно, слово «кошмар» было неправильным: оно было очень неудобным. Мы не сильно пострадали от проблем с целостностью данных.
user128216
7

это зависит от того, какую роль это foreign keyиграет в ваших отношениях.

  1. если это foreign keyтакже key attributeв вашем отношении, то это не может быть NULL
  2. если это foreign keyнормальный атрибут в вашем отношении, то он может быть NULL.
shinxg
источник
3

Вот пример использования синтаксиса Oracle:
сначала давайте создадим таблицу COUNTRY

CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;

Создать таблицу ПРОВИНЦИЯ

CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID  VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;

Это прекрасно работает в Oracle. Обратите внимание, что внешний ключ COUNTRY_ID во второй таблице не имеет "NOT NULL".

Теперь, чтобы вставить строку в таблицу PROVINCE, достаточно указать только PROVINCE_ID. Однако, если вы решили указать и COUNTRY_ID, он должен уже существовать в таблице COUNTRY.

Mouhcine
источник
1

По умолчанию нет никаких ограничений на внешний ключ, внешний ключ может быть нулевым и повторяться.

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

нитин лалвани
источник
0

Проще говоря, «неидентифицирующие» отношения между сущностями являются частью ER-модели и доступны в Microsoft Visio при разработке ER-диаграммы. Это необходимо для обеспечения количества элементов между сущностями типа «ноль или более нуля» или «ноль или единица». Обратите внимание на это «ноль» в количестве элементов вместо «один» в «один ко многим»

Теперь пример неидентифицирующих отношений, где количество элементов может быть «ноль» (неидентифицирующий), - это когда мы говорим, что запись / объект в одном объекте-A «может» или «не может» иметь значение в качестве ссылки на запись / s в другой сущности-B.

Так как существует возможность для одной записи объекта-A идентифицировать себя с записями другого объекта-B, поэтому в Entity-B должен быть столбец, чтобы иметь значение идентификатора записи объекта-B. Этот столбец может быть нулевым, если ни одна запись в Entity-A не идентифицирует запись (и), или объект (ы) в Entity-B.

В объектно-ориентированной (реальной) парадигме существуют ситуации, когда объект класса B не обязательно зависит (сильно связан) от объекта класса A в своем существовании, что означает, что класс B слабо связан с классом Такой, что класс А может «содержать» (сдерживать) объект класса А, в отличие от концепции объекта класса В, должен иметь (композицию) объект класса А для его (объекта класса). Б) создание.

С точки зрения SQL-запроса, вы можете запросить все записи в entity-B, которые являются "ненулевыми" для внешнего ключа, зарезервированного для Entity-B. Это приведет к тому, что все записи, имеющие определенное соответствующее значение для строк в Entity-A, в качестве альтернативы, все записи со значением Null будут теми записями, которые не имеют никаких записей в Entity-A в Entity-B.

Фахар
источник
-1

Я думаю, что лучше рассмотреть возможную мощность в таблицах. Мы можем иметь минимально возможную нулевую мощность. Когда это необязательно, минимальное участие кортежей из связанной таблицы может быть равно нулю. Теперь вы сталкиваетесь с необходимостью использования значений внешнего ключа равными нулю.

Но ответ - все зависит от бизнеса.

user9274383
источник
-3

Идея внешнего ключа основана на концепции ссылки на значение, которое уже существует в основной таблице. Вот почему он называется внешним ключом в другой таблице. Эта концепция называется ссылочной целостностью. Если внешний ключ объявлен как нулевое поле, это нарушит саму логику ссылочной целостности. На что это будет ссылаться? Это может относиться только к тому, что присутствует в основной таблице. Следовательно, я думаю, что было бы неправильно объявлять поле внешнего ключа пустым.

SQLDev
источник
Он может ссылаться на «ничто» или вы еще не знаете его значение NULL, но что говорит ссылочная целостность, так это то, что если он ссылается на «что-то», он должен быть там.
Якс
-7

Я думаю, что внешний ключ одной таблицы также является первичным ключом какой-то другой таблицы. Так что он не допускает нулевые значения. Поэтому не возникает вопроса о наличии нулевого значения во внешнем ключе.

user4532553
источник