Помірна практика, що не стосується іноземних ключів?


114

Скажімо, у вас є таблиця Замовлення із іноземним ключем до ідентифікатора клієнта. Тепер, припустимо, ви хочете додати замовлення без ідентифікатора клієнта, (чи має бути це можливо - це інше питання), вам доведеться зробити зовнішній ключ NULL ... Це погана практика чи ви б краще працювали з таблицею посилань між Замовлення та замовники? Хоча відношення є 1 до n, таблиця посилань зробить це n до n. З іншого боку, із таблицею посилань я більше не маю цих НУЛІВ ...

Насправді в базі даних не буде багато NULL, тому що запис із зовнішнім ключем до NULL просто тимчасово, поки клієнт для замовлення не буде доданий.

(У моєму випадку це не Замовлення та Клієнт).

РЕДАКТ: Що з непризначеним Клієнтом для посилання?


9
Це є однією з головних цілей забезпечення доступності NULL в схемі бази даних. Крім того, саме тому ви можете оголосити поля NULL або NOT NULL, щоб відповідати конкретним вимогам вашої схеми.
gahooa

7
Я спочатку прочитав питання як "Nullable Primary keys", і вже збирався проникнути з деякими настійними порадами ... :-)
Анджей Дойл

Відповіді:


51

Маючи таблицю посилань, мабуть, кращий варіант. Принаймні, це не порушує нормалізації BCNF (нормальна форма Бойса-Кодда). однак я хотів би бути прагматичним. Якщо цих нульових значень у вас дуже мало, і вони є лише тимчасовими, я думаю, вам слід пропустити таблицю посилань, оскільки це лише додає складності схемі.

На бічній записці; за допомогою таблиці посилань не обов'язково робити це n до n, якщо ви в таблиці посилань використовуєте зовнішній ключ, який вказує на таблицю ваших замовлень як основний ключ у цій таблиці посилань, зв’язок все ще становить 1..n. У цій таблиці посилань може бути лише один запис у кожному посиланні.


2
source__destination_link або SourceDestination
Svisstack

7
Мені було б цікаво почути ситуацію, коли краще мати таблицю посилань, я ніколи не стикався з ситуацією, коли це би покращило потоки процесів будь-яким способом.
Реймій

5
Як було зазначено у моїй відповіді, я буду прагматичним у цьому конкретному випадку і не використовую таблицю посилань. Я впевнений, що нормальні форми не були придумані для покращення потоку процесу, а для забезпечення послідовності та уникнення надмірності. Хоча це дуже загальна дискусія, я думаю, що це потрібно розглядати у кожному конкретному випадку.
Patrik Hägne

110

Ні З Nullable FK не буває нічого поганого. Це звичайно, коли сутність, на яку вказує FK, перебуває у відносинах (нуль або один) до (1 або багато) з таблицею, на яку посилається первинний ключ.

Прикладом може бути, якщо у вас були як фізична адреса, так і атрибут (стовпець) адреси електронної пошти (таблиця) у таблиці, з FKs до таблиці адрес. Ви можете зробити фізичну адресу зведеною для оброблення, коли суб'єкт господарювання має лише поштове вікно (поштова адреса), а поштову адресу - зведеною для обробки, коли поштова адреса збігається з фізичною адресою (чи ні).


39

Зменшувані стовпці можуть бути від 1NF до 5NF, але не в 6NF відповідно до того, що я прочитав.

Тільки якщо ти краще знаєш, ніж Кріс Дата, "що означає перша нормальна форма насправді". Якщо x і y обидва є нульовими, і справді в якомусь рядку x і y є обома null, то WHERE x=yце не поступається true. Це доводить поза розумним сумнівом, що null не є величиною (тому що будь-яка реальна цінність завжди сама собі рівна). А оскільки RM прописує, що "повинно бути значення у кожній комірці таблиці", будь-яка річ, яка, можливо, містить нулі, не є реляційною річчю, і тому питання про 1NF навіть не виникає.

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

Дивіться вище щодо обґрунтованої причини, яка лежить в основі цього аргументу.

Але на практиці це дуже практично.

Тільки якщо ви не застраховані від головних болів, які вони зазвичай викликають у всьому іншому світі. Одним із таких головних болів (і це лише незначний, порівняно з іншими nullфеноменами) є той факт, що WHERE x=yв SQL насправді означаєWHERE x is not null and y is not null and x=y , але що більшість програмістів просто не знають цього факту і просто читають його. Іноді без жодної шкоди, інший раз ні.

Насправді, зведені стовпці порушують одне з найважливіших правил проектування бази даних: не поєднуйте в одному стовпчику окремих інформаційних елементів. Нулі роблять саме так, оскільки вони поєднують булеве значення "це поле є / насправді немає" з фактичним значенням.


18
+1 для "WHERE x не є null і y не null, а x = y". Не знав цього.
RobM

1
Дуже добре викладені аргументи та приклади.
pedz

1
Одна проблема. Коли значення "не існує" (Який сценарій реального світу), а атрибут бази даних не дозволяє нульових значень, будь-яке значення в атрибуті WRONG. Що стосується головних болів, пам’ятайте, KISS, це не означає просто робити це просто, це означає Тримати це максимально просто, але не простіше. Якщо "реляційна модель" вимагає нереального, дурного результату, то, можливо, правила потрібно розширити, щоб обробити необхідні дані в реальному світі?
Чарльз Бретана

1
Було показано, що тризначна логіка призводить до потреби у чотиризначній логіці, і це призводить до потреби у п'ятизначній логіці тощо. Двозначна логіка є достатньою, але структури даних, які ми отримуємо, коли застосовуючи його, роблять "максимально простим", але все ж набагато менш простим, ніж "таким простим, як ми хотіли б".
Ервін Смоут

2
Chris Date, Logic & Databases, Chpt 6, "Чому логіка реляційних СУБД не повинна бути багатозначною", стор. 145. Список посилань на цю главу також повинен бути цікавим, особливо тих, що стосуються McGoveran.
Ервін Смоут

13

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


2
Насправді це відносини 0-N, а не необов'язкові відносини 1-N. Але я з вами згоден.
Ерік Дж.

5
Управління? Це просте УНІКАЛЬНЕ обмеження на стороні 0 на 1!
wqw

2
Так, це УНІКАЛЬНЕ обмеження, але вам також доведеться мати справу з можливими винятками пізніше у своєму коді через це обмеження ...
pedromarce

4

Необов'язкові відносини, безумовно, можливі в реляційній моделі.

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

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


2

Використання NULL було б хорошим способом очищення неповних замовлень:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Вищенаведені покази замовлень старше 15 хвилин без відповідного ідентифікатора клієнта.


1

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

Зазвичай така ситуація виникає у веб-додатках, де докладно деталізується замовлення, перш ніж клієнт визначить, хто він / вона. І в таких ситуаціях замовлення зберігається в стані сервера або в файлі cookie до тих пір, поки не буде надано весь необхідний стан для повного замовлення, в який момент замовлення зберігається в базі даних.

Іноземні ключі NULL в порядку для таких речей, як зазначено вище. Але поле NULL для клієнта не має сенсу для замовлення, і його слід обмежувати.


Приклад-замовник був прикладом. У моєму додатку він idd більше схожий на адреси. Не вдалося відразу знайти приклад, який був правильним весь шлях. Дякую.
Лівен Кардоен

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

1

Ви завжди можете додати до таблиці клієнтів штучний рядок, наприклад Id = -1 та CustomerName = "Невідомий", а потім у випадках, коли ви зазвичай встановлюєте CustomerId у Order NULL, це -1.

Це дозволяє вам не мати змінних ФК, але все-таки належним чином представляти брак даних (і позбавить вас від користувачів, що не входять у рух, не знаючи, як боротися з NULL).


Для того, щоб додати до цього, пам’ятайте, що NULLS не зберігаються в індексі (в оракулі), тому це означає, що пропуск таблиці посилань та перехід на нульовий FK має сенс - ефективність мудра. Інша річ, від якої це може залежати, - це якщо ви хочете зберігати щось інше у цій таблиці посилань, наприклад, хто ВОЗ зробив посилання і коли? Зараз посилання неактивне / видалене (але колись було?)
Варто7

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

0

Незмінні ФК для необов'язкових відносин багато-до-одного абсолютно добре.


-1

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


3
Зменшувані стовпці можуть бути від 1NF до 5NF, але не в 6NF відповідно до того, що я прочитав.
Вальтер Мітті

-1

Так, це щось не так. Це не іноземний ключ, якщо його нульовий. Його дизайн бази даних за кодом. Можливо, ви зробите нульове посилання на непризначене. або "Неприсвоєно", якщо ви використовуєте знак символів. Зберігайте цілісність своїх даних на 100%.

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