Чи може іноземний ключ бути NULL та / або дублювати?


325

Прошу уточнити дві речі для мене:

  1. Чи може іноземний ключ бути NULL?
  2. Чи може іноземний ключ бути дублікатом?

Як справедливо, як я знаю, NULLне слід використовувати в іноземних ключах, але в моєму додатку я можу ввести NULLі Oracle, і SQL Server, і я не знаю, чому.


1
@Adrian: Найкраще, наскільки мені відомо, зовнішній ключ не може бути нульовим, але він займає null у sql сервері та oracle. ви можете пояснити, чому?
джеми

@Jams - прочитайте посилання у моїй відповіді.
JNK

11
це неможливо видалити, оскільки відповіді та запитання корисні. Не соромтесь редагувати питання, щоб вдосконалити його.
Джефф Етвуд

Будь ласка, розділіть питання про дублікати. Нижче наведено лише відповідь про NULL.
reinierpost

Відповіді:


527

Коротка відповідь: Так, це може бути NULL або дублікат.

Я хочу пояснити, чому зовнішній ключ може знадобитися нульовим або може бути унікальним чи неповторним. Спершу запам’ятайте Закордонний ключ просто вимагає, щоб значення в цьому полі спочатку мало існувати в іншій таблиці (батьківській таблиці). Тобто все FK є за визначенням. Нуль за визначенням не є значенням. Нульовий означає, що ми ще не знаємо, яка цінність.

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

Незалежно від того, унікальна вона чи не унікальна, це стосується того, чи таблиця має відношення один-один чи один-багато до батьківської таблиці. Тепер, якщо у вас є стосунки один на один, можливо, ви могли б мати дані всі в одній таблиці, але якщо таблиця стає занадто широкою або якщо дані на іншу тему (співробітник - приклад страхування @tbone дав наприклад), тоді вам потрібно окремі таблиці з FK. Тоді ви хочете зробити цей ФК також або ПК (що гарантує унікальність), або поставити на нього унікальне обмеження.

Більшість ФК мають стосунки один до багатьох, і саме це ви отримуєте від ФК, не додаючи додаткових обмежень на полі. Отже, у вас є таблиця замовлень і, наприклад, таблиця деталей замовлення. Якщо замовник замовляє десять товарів одночасно, у нього є одне замовлення та десять записів деталей замовлення, які містять той самий ID замовлення, що і FK.


13
Отже, це призначено краще, ніж мати фальшиву людину з продажу на ім'я "Непризначений"?
Томас Веллер

8
Коментар. Нулі залишають багато місця для помилок у запиті людей, які не знають, як SQL (міс) обробляє 3VL. Якщо продавцю справді не потрібен певний r-таблицю, просто ви не включаєте цю запис. Окремою таблицею може бути "OfferAssignedTo" або якась така, з відповідними обмеженнями. Потім автор запитів може приєднатися до цієї таблиці та подати власну логіку для того, що ми хочемо зробити, коли пропозиція не має продавця. NULL не означає просто "ми не знаємо" - його можна використовувати для багатьох речей (через що майже завжди це погана ідея)
N West

26
@nWest, я не дозволяю людям, які є некомпетентними, запитувати мої бази даних, а будь-який розробник, який не знає, як обробляти нулі, некомпетентний. Бувають випадки, коли дані не відомі під час початкового введення даних для певного поля, але інші поля потрібні на той час.
HLGEM

28
@ThomasWeller Посилання на підробленого продавця ("Непризначений") робить проблему ще гіршою. Я припускаю, що у таблиці вашого продавця є кілька стовпців ...? Який номер соціального страхування містера Непризначеного? У який відділ він призначений? Хто його начальник? Я сподіваюся, що ви зрозумієте: коли ви створюєте продавця "Непризначений", ви швидко виявите, що ви торгували NULLв одній таблиці по декілька NULLs в іншій таблиці.
Гілі

1
@ThomasWeller У вас також виникне проблема, якщо / коли вам потрібно локалізувати свій інтерфейс.
tobiv


45

З вуст коня:

Іноземні ключі дозволяють використовувати ключові значення, які є всі НУЛІ, навіть якщо немає відповідних ПРИМІТНИХ або УНІКАЛЬНИХ ключів

Жодних обмежень на зовнішній ключ

Якщо на зовнішньому ключі не визначено інших обмежень, будь-яка кількість рядків у дочірній таблиці може посилатися на те саме значення батьківського ключа. Ця модель дозволяє отримати нулі в зовнішньому ключі. ...

НЕ NULL обмеження на зовнішній ключ

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

Будь-яка кількість рядків у дочірній таблиці може посилатися на одне і те ж значення батьківського ключа, тому ця модель встановлює взаємозв'язок між батьківським та зовнішнім ключами. Однак кожен рядок у дочірній таблиці повинен мати посилання на значення батьківського ключа; відсутність значення (нуля) в зовнішньому ключі не допускається. Цей же приклад у попередньому розділі може бути використаний для ілюстрації такого взаємозв'язку. Однак у цьому випадку працівники повинні мати посилання на певний відділ.

Унікальне обмеження на зовнішній ключ

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

Ця модель встановлює взаємовідносини один на один між батьківським та зовнішнім ключами, що дозволяє визначити в зовнішньому ключі невизначені значення (нулі). Наприклад, припустимо, що в таблиці працівника була стовпець з назвою МЕМБЕРНО, посилаючись на номер членства працівника в плані страхування компанії. Також у таблиці під назвою СТРАХУВАННЯ є первинний ключ з іменем MEMBERNO, а в інших стовпцях таблиці зберігається відповідна інформація, що стосується страхового полісу працівника. MEMBERNO в таблиці співробітників має бути як зовнішнім ключем, так і унікальним ключем:

  • Застосовувати референтні правила цілісності між таблицями EMP_TAB та СТРАХУВАННЯ (обмеження КОРОТКОГО ЗАБЕЗПЕЧЕННЯ)

  • Гарантувати, що кожен працівник має унікальний номер членства (UNIQUE key constract)

Унікальні та НЕ НУЛЬНІ обмеження на зовнішньому ключі

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

Дивіться це:

Посилання Oracle 11g


16

Так, зовнішній ключ може бути недійсним, як сказано вище старшими програмістами ... Я б додав ще один сценарій, коли зовнішній ключ повинен бути нульовим .... припустимо, у таблиці є коментарі до таблиць, зображень та відео в додатку, який дозволяє коментувати фотографії та відео. У таблиці коментарів ми можемо мати два іноземних клавіші PicturesId та VideosId, а також основний ключ коментаря. Тож, коли ви коментуватимете відео, потрібен би лише VideoId, а pictureId буде нульовим ... а якщо ви коментуєте зображення, потрібен буде лише PictureId, а VideosId буде нульовим ...


1
Я думаю, що є кращий спосіб вирішити цю проблему. Замість того, щоб створювати нові стовпці, ви можете мати два стовпці, а саме "id" та "type", які містять ідентифікатор та ім'я таблиці зовнішнього ключа. Наприклад, id = 1, type = Зображення представлятиме посилання на таблицю зображень з id 1. Перевагою використання цього рішення є те, що вам не доведеться створювати нові стовпці, коли коментарі додаються до додаткових таблиць. Недоліком не буде обмеження зовнішнього ключа на рівні db, скоріше обмеженням має бути рівень програми.
Agent47DarkSoul

4
@Agent: У нас було таке "рішення" у виробництві. Не робіть цього, це жахливо. Здійснення запитів стає таким безладом, "якщо це тип 1, приєднуйтесь до цієї таблиці, інакше приєднуйтесь до цієї". Для нас це був кошмар. Ми закінчилися тим, що говорить ця відповідь, і створили нову колонку для кожного типу приєднання. Створення колон дешево. Насправді, лише недоліком є ​​те, що багато стовпців робить Toad важким у використанні, але це лише недолік жаби.
користувач128216

1
@FighterJet Rails пропонує чудову структуру ORM, яка обробляє навіть складні запити за допомогою цього рішення.
Agent47DarkSoul

2
@Agent: Можливо, це може ... але якщо ви можете зробити це просто, навіщо робити це складним? І, можливо, «кошмар» було неправильним уживанням: це було просто дуже незручно. Ми не страждали від проблем цілісності даних (багато).
користувач128216

7

це залежить від того, яку роль це foreign keyграє у ваших стосунках.

  1. якщо це foreign keyтакож є key attributeу ваших стосунках, то воно не може бути NULL
  2. якщо це foreign keyнормальний атрибут у ваших стосунках, то він може бути NULL.

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.


1

За замовчуванням на зовнішньому ключі немає обмежень, зовнішній ключ може бути нульовим і дублюючим.

створюючи таблицю / змінюючи таблицю, якщо ви додаєте будь-яке обмеження унікальності чи не нульове значення, то лише воно не дозволить значенням "null / duplicate".


0

Простіше кажучи, "Неідентифікаційні" відносини між Суб'єктами є частиною ER-моделі і доступні в Microsoft Visio при розробці ER-діаграми. Це потрібно для забезпечення кардинальності між сутностями типу "нуль або більше нуля", або "нуль або один". Зверніть увагу на цей "нуль" у кардинальності замість "один" у "один до багатьох".

Тепер, приклад неідентифікаційного зв’язку, де кардинальність може бути "нульовим" (неідентифікаційний), - це коли ми кажемо, що запис / об'єкт в одному об'єкті - "може" або "не може" мати значення як посилання на запис / s в іншому об'єкті-B.

Оскільки існує можливість одного запису сутності-A ідентифікувати себе в записах іншої сутності-B, тому в Entity-B повинен бути стовпець, який має значення ідентичності запису Entity-B. Цей стовпець може бути "Нульовим", якщо жодна запис у Entity-A не ідентифікує запис / s (або, об'єкт / s) в Entity-B.

У парадигмі, орієнтованій на об'єкти (у реальному світі), бувають ситуації, коли об'єкт класу B не обов'язково залежить (сильно зв'язаний) від об'єкта класу A за його існування, а це означає, що клас B є вільно поєднаний із класом Такий, що Class-A може "містити" (містити) об'єкт класу A, на відміну від поняття об'єкта класу-B, повинен мати (склад) об'єкт класу-A, для його (об'єкт class- Б) створення.

З точки зору SQL Query, ви можете запитувати всі записи в сутності-B, які "не нульові" для зовнішнього ключа, зарезервованого для Entity-B. Це призведе до того, що всі записи, що мають певне відповідне значення для рядків у Entity-A, або ж усі записи з нульовим значенням стануть записами, у яких немає запису в Entity-A в Entity-B.


-1

Я думаю, що краще врахувати можливу кардинальність, яку ми маємо в таблицях. У нас може бути можливий мінімальний нуль кардинальності. Якщо це необов'язково, мінімальна участь кортежів із пов’язаної таблиці може бути нульовою. Тепер ви стикаєтесь з необхідністю, щоб іноземні ключові значення мали бути недійсними.

Але відповідь: все залежить від бізнесу.


-3

Ідея іноземного ключа заснована на концепції посилання на значення, яке вже існує в головній таблиці. Ось чому його називають іноземним ключем в іншій таблиці. Ця концепція називається референтною цілісністю. Якщо зовнішній ключ буде оголошено нульовим полем, він порушить саму логіку референсної цілісності. Що це стосуватиметься? Він може стосуватися лише того, що є в головній таблиці. Отже, я думаю, що було б неправильним оголошувати зовнішнє ключове поле нічим.


Він може посилатися на "нічого" або ви ще не знаєте його значення NULL, але те, що референтна цілісність говорить, це те, що якщо воно посилається на "щось", воно повинно бути там.
ясе

-7

Я думаю, що зовнішній ключ однієї таблиці також є первинним ключем до якоїсь іншої таблиці. Тому він не дозволяє нулю. Тому немає питання про наявність нульового значення в зовнішньому ключі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.