Нормализация отношений 1: 1 или 1: 0 - PullRequest
3 голосов
/ 03 марта 2011

при использовании реляционных баз данных, и вы хотите 3NF (вы называете это 3NF по-английски?), Тогда вы объединяете отношения 1: 1 в одну таблицу.Но что произойдет, если соотношение составляет 1: 0/1 (/ означает или)?

Тогда вы держите их разделенными, чтобы избежать пробелов в таблицах?Разделяя их, в этом случае действует 3NF?

Ответы [ 3 ]

3 голосов
/ 03 марта 2011

Основываясь на вашем вопросе и последующих комментариях к ответу @ paxdialbo, я понимаю, что вам нужно решение для хранения необязательных атрибутов, которых много, и при этом следует избегать значений NULL. Два способа сделать это: 6-я нормальная форма (6NF) или Значение атрибута объекта (EAV).

6-я нормальная форма

Это включает создание таблицы, специфичной для атрибута:

create table attributeName (
    id
    value
)

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

Значение атрибута сущности

Теперь, как вы можете себе представить, 6-я нормальная форма может привести к быстрому размножению стола. Модель EAV решается с использованием аналогичной модели для нескольких атрибутов, таких как:

create table integerAttribute (
    name
    id
    value
)

В столбце name указан атрибут (например, «SocialSecurity»), хотя вместо столбца name используется более сложная реализация, name хранится в отдельной таблице метаданных и ссылается через внешний ключ. Независимо от этого, данный подход подразумевает наличие других таблиц для разных типов данных (т. Е. datetimeAttribute, varcharAttribute и т. Д.).

Заключение

Реальный вопрос для размышления - сколько дополнительных атрибутов вы имеете дело. Если их относительно мало, проще всего добавить необязательные столбцы NULLable в основную таблицу. 6NF и EAV добавляют значительную сложность и проблемы производительности. Часто при использовании одного из этих подходов сериализуется весь объект в CLOB на главной таблице, чтобы упростить общее чтение (т. Е. По первичному ключу), чтобы избежать множественных соединений LEFT для получения полностью гидратированного объекта.

3 голосов
/ 03 марта 2011

Третья нормальная форма в основном означает, что атрибут (или столбец) зависит от ключа, всего ключа и ничего, кроме ключа (так что помогите мне, Кодд).

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

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

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

Далее предположим, что у вас есть отличительный атрибут BankAccount для выплаты их заработной платы, и что вы не один из тех хороших работодателей, которые могут распределять заработную платуна несколько банковских счетов с целью уклонения от налогов: -)

Теперь банковский счет кого-либо полностью зависит от thВыбранный ключ, но не каждый может иметь его (они могут быть оплачены наличными).Другими словами, классический 1:0/1 случай, как вы его назвали.

В этом случае вы просто сделаете номер банковского счета обнуляемым в таблице.

2 голосов
/ 05 марта 2011

Опираясь на ваши комментарии с paxdiablo. , .

Давайте посмотрим на некоторые SQL. Я мог бы выбрать лучшие имена для столбцов, но я сознательно не сделал. Я не был ленивым; У меня были веские причины. Внешний предикат - это то, как пользователи должны интерпретировать содержимое таблицы.

-- External predicate: Human is identified by 
--                         Social Security Account Number [ssan] 
--                     and has full name [full_name] 
--                     and result of last HIV test [hiv_status]
--                     and has checking account [bank_account]
--                     and was born at exactly [birth_date].
--
create table human (
ssan char(9) primary key, 
full_name varchar(35) not null,
hiv_status char(3) not null default 'Unk' 
    CHECK (hiv_status in ('Unk', 'Pos', 'Neg')),
bank_account varchar(20),
birth_date timestamp not null
);

-- External predicate: Human athlete identified by 
--                         Social Security Account Number [ssan] 
--                     has current doping status [doping_status]
create table athlete (
ssan char(9) not null primary key references human (ssan),
doping_status char(3) not null default 'Unk' 
    CHECK (doping_status in ('Unk', 'Pos', 'Neg'))
);

-- External predicate: Human dictator identified by 
--                         Social Security Account Number [ssan] 
--                     has estimated benevolence of [benevolence_score].
create table dictator (
ssan char(9) not null primary key references human (ssan),
benevolence_score integer not null default 3 
    CHECK (benevolence_score between 1 and 5) -- 1 is least, 5 is most benevolent
);

Все три из этих таблиц в 5NF. (Это означает, что они также в 3NF.)

Вы сказали

нет отношения "есть" в реляционная база данных

Спортсмен "Я" человек, потому что его идентификатор - это человеческий идентификатор. В этом случае его первичным ключом является внешний ключ, который references human (ssan). Разработчики баз данных обычно не говорят в терминах отношений «IS A» и «HAS A», потому что предикаты являются более точными и выразительными. Вы можете увидеть разницу, сравнив эти два утверждения.

  • человек "ИМЕЕТ" [дата рождения]
  • человек родился именно в [Birth_date]

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

Вы сказали

Но теперь вы все равно получите чистого ЧЕЛОВЕКА но только дети ЧЕЛОВЕКА

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

SELECT * FROM human;

Если вы имеете в виду, что у вас не может быть человека, если человек не является спортсменом или диктатором (или чем-то еще), тогда вы ошибаетесь. Если в спортсмене нет строки для определенного SSAN, то человек, идентифицированный этим SSAN, не является спортсменом. Если в диктаторе нет строки для определенного SSAN, то человек, идентифицированный этим SSAN, не является диктатором.

...