значение по умолчанию или значение NULL для внешнего ключа

У меня вопрос об использовании значения NULL или значения по умолчанию для столбцов внешнего ключа в базе данных. Я нашел много противоположных мнений о значениях null и значениях по умолчанию при разработке баз данных, но не только о внешних ключах (каковы основные плюсы и минусы).

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

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

Теперь у меня есть два / три варианта:

A: Я разрешаю столбцу NationalityID (и всем другим аналогичным столбцам внешнего ключа в базе данных) иметь значение NULL и просто придерживаюсь общего подхода проверки всегда и везде на значение NULL (применение правил в приложении)

or

B: Я назначаю значение по умолчанию для каждого внешнего ключа, скажем, «-1», и помещаю в каждую таблицу отношений дополнительный столбец с «-1» в качестве ключа, а все другие данные - как «Нет данных» (для этого примера в Country table я помещаю столбец с CountryID "-1" и для CountryName я устанавливаю "Нет данных"). Таким образом, каждый раз, когда я захочу узнать национальность пользователей, я всегда буду получать результат без дополнительных правил кода (мне не нужно проверять, является ли он нулевым или нет).

or

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

Итак, B - хороший подход или нет? Что мне здесь не хватает? Теряю ли я больше, чем получаю при таком подходе? Какие проблемы могут возникнуть у меня (помимо того, что нужно всегда иметь дополнительный столбец в реляционных таблицах со значением ID «-1», что означает «Нет данных»)?

Каков ваш хороший / плохой опыт работы со значениями по умолчанию внешнего ключа?

Спасибо


person Janez    schedule 15.04.2011    source источник


Ответы (5)


Если вы нормализуете, это не будет проблемой.

Вместо того, чтобы указывать национальность в таблице USER, создайте таблицу User_Nationality, которая связывает пользователей с Country_ID в другой таблице.

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

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

Используйте таблицы поиска, и вы можете полностью обойти это.

Это также позволит вам передумать и в будущем выбрать один из вариантов.

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

person JNK    schedule 15.04.2011
comment
Я думаю, что с таблицами поиска данные будут слишком фрагментированы. Только для пользователей мне понадобится минимум 10 таблиц поиска только для пользователей (есть много разных данных, таких как национальность для пользователей, которые мне нужно обработать). А пользователи - это всего лишь небольшая часть всей базы данных (нам нужно обрабатывать данные о работе, обязательствах, действиях, безопасности и многом другом). У меня будет 100+ столов очень быстро ... это цена, которую мне нужно заплатить? - person Janez; 15.04.2011
comment
Это самое надежное решение. Вы потратите много времени на его создание, но как только он будет установлен, его будет намного легче поддерживать. Это также позволит вам добавлять критерии в будущем без необходимости полностью переделывать вашу таблицу пользователей. - person JNK; 15.04.2011
comment
Как тогда грамотно справиться с проблемой нескольких записей для одного и того же пользователя в таблице поиска? Как я уже упоминал, я хочу, чтобы общие правила применялись на самом низком уровне базы данных. ПРОБЛЕМА: если я создаю отдельную таблицу для хранения страны рождения пользователя, например, мне нужно применить какое-то дополнительное правило, чтобы избежать наличия человека с двумя странами рождения. А также, когда я хочу вставить страну рождения пользователя, мне всегда нужно сначала проверить, существует ли уже запись для страны рождения, а затем обработать вставку или обновление. Извините, если я привел глупый пример, надеюсь, вы понимаете, что я хочу указать :) - person Janez; 15.04.2011
comment
@Janez - Очень-очень-очень просто - Сделайте PRIMARY KEY или UNIQUE CONSTRAINT в поле User_Id в таблицах поиска. Таким образом, механизм БД разрешит только одну строку на user_id. - person JNK; 15.04.2011
comment
Я знаю об ограничениях, и мне кажется, что это лучшее решение (по крайней мере, в моем случае). Я думаю, что буду продолжать использовать этот подход с помощью таблицы поиска для моей базы данных. Но теперь мне также нужно найти способ для базы данных автоматически обрабатывать ограничения: если кто-то хочет вставить значение для пользователя, которое уже существует в таблице поиска, отбросьте вставку для этой таблицы и вместо этого обновите существующую (может быть, триггеры?). Таким образом я добьюсь применения глобального правила на уровне базы данных (нет необходимости обрабатывать его отдельно в миллионах приложений миллионами разных способов). Еще раз спасибо ... пока :) - person Janez; 15.04.2011
comment
@Janez - для этого можно использовать триггер INSTEAD OF - person JNK; 15.04.2011
comment
Вам необходимо обеспечить соблюдение отношений FK, а разрешение NULL противоречит этому. Эммм, ЧТО ?? Обнуляемые FK как раз предназначены для этого (принудительные необязательные отношения). Предлагаемое вами решение усложняет работу и снижает производительность. - person Diego Mijelshon; 17.04.2011
comment
+1 за использование отдельной таблицы, но я бы не назвал это таблицей поиска. В контексте справочная таблица будет содержать все возможные значения домена, которые могут появиться в таблице User_Nationality, что, вероятно, было бы плохой идеей в этом случае, поскольку национальность является потенциально чувствительной проблемой (мой отец - кубинец, а моя мать - исландка, поэтому я ...? :) - person onedaywhen; 27.04.2011
comment
@onedaywhen - Тогда извините за таблицу ссылок :) - person JNK; 27.04.2011

Лично мне кажется, что даже если в вашей базе данных есть запись без записи с ключом -1, вы все равно будете проверять, хотите ли вы отображать «Нет данных» для каждого отдельного поля.

Я бы придерживался NULL. NULL означает отсутствие данных, что и имеет место здесь.

person Jeff Lambert    schedule 15.04.2011
comment
У меня есть много сценариев, в которых мне будет возвращено значение «Нет данных» (без дополнительного кода, требуются проверки). В любом случае я буду использовать подход с помощью таблиц поиска, спасибо за указание на это - person Janez; 16.04.2011

Б - ужасный подход. Легче вспомнить, как обрабатывать нули, чем выяснять, какое магическое число вы использовали, и тогда вам все равно придется их обрабатывать. Используйте номер 1. Но мне больше всего нравится идея JNK.

person HLGEM    schedule 15.04.2011

Я предлагаю вариант D. Если не все пользователи имеют определенную национальность, то этой информации нет в таблице пользователей. Создайте таблицу с именем UserNationality с ключом UserId.

person nvogel    schedule 15.04.2011
comment
это снова подход с использованием таблиц поиска, который также предложил JNK. Спасибо - person Janez; 16.04.2011

Мне нравится ваше решение Б. Возможно, удастся сопоставить значения с другими объектами, поэтому у вас есть Country и NullCountry, который расширяет Country и отображается на строку с id = -1 и имеет специальный код в своих методах, чтобы упростить обработку особых случаев.

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

РЕДАКТИРОВАТЬ: нет, проблем с внешними соединениями быть не должно, потому что не было бы необходимости делать внешние соединения.

person ajuc    schedule 15.04.2011