Опции для устранения ненужных колонн от модели БД (чтобы избежать трехзначной логики SQL)?

StackOverflow https://stackoverflow.com/questions/3079885

Вопрос

Некоторое время назад я читал через книгу SQL и реляционная теория CJ Date.. Отказ Автор хорошо известен критикой трехзначной логики SQL (3VL).1)

Автор делает некоторые сильные моменты о том, почему 3VL следует избегать в SQL, однако он не обрисован Как будет выглядеть модель базы данных, если не допускаются нулевые столбцы. Отказ Я немного подумал об этом и придумал следующие решения. Если я пропустил другие варианты дизайна, я хотел бы услышать о них!

1) Дата Критика 3VL SQL 3VL также подверглась критике: см. Эта статья Claude Rubinson (включает в себя оригинальную критику CJ Date).


Пример таблицы:

В качестве примера возьмите следующую таблицу, где у нас есть один изнушный столбец (DateOfBirth):

#  +-------------------------------------------+
#  |                   People                  |
#  +------------+--------------+---------------+
#  |  PersonID  |  Name        |  DateOfBirth  |
#  +============+--------------+---------------+
#  |  1         |  Banana Man  |  NULL         |
#  +------------+--------------+---------------+

Вариант 1: эмуляция NULL через флаг и значение по умолчанию:

Вместо того, чтобы сделать столбец Nulleable, указано любое значение по умолчанию (например, 1900-01-01). Дополнительный BOOLEAN столбец укажет, будет ли значение в DateOfBirth следует просто игнорировать или на самом деле содержит данные.

#  +------------------------------------------------------------------+
#  |                              People'                             |
#  +------------+--------------+----------------------+---------------+
#  |  PersonID  |  Name        |  IsDateOfBirthKnown  |  DateOfBirth  |
#  +============+--------------+----------------------+---------------+
#  |  1         |  Banana Man  |  FALSE               |  1900-01-01   |
#  +------------+--------------+----------------------+---------------+

Вариант 2: Отключение оттудаваемого столбца в отдельную таблицу:

Знаменитая колонна заменяется новой таблицей (DatesOfBirth). Если запись не имеет данных для этого столбца, в новой таблице не будет запись:

#  +---------------------------+ 1    0..1 +----------------------------+
#  |         People'           | <-------> |         DatesOfBirth       |
#  +------------+--------------+           +------------+---------------+
#  |  PersonID  |  Name        |           |  PersonID  |  DateOfBirth  |
#  +============+--------------+           +============+---------------+
#  |  1         |  Banana Man  |
#  +------------+--------------+

Хотя это кажется лучшем решением, возможно, приведет к тому, что необходимо привести к тому, что необходимо присоединиться к одному запросу. С OUTER JOINs не будет разрешено (потому что они будут представлены NULL В набор результатов) все необходимые данные могут больше не быть достаточными с одним запросом, как раньше.


Вопрос:Есть ли другие варианты для устранения NULL (И если так, что они)?

Это было полезно?

Решение

Я видел коллегу даты Хью Дарвана, обсуждаю эту проблему в отличной презентации «Как обрабатывать недостающую информацию без использования NULL», которая доступна на Третий сайт манифеста.

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

#  +-----------------------------+ 1    0..1 +----------------------------+
#  |         People'             | <-------> |         DatesOfBirth       |
#  +------------+----------------+           +------------+---------------+
#  |  PersonID  |  Name          |           |  PersonID  |  DateOfBirth  |
#  +============+----------------+           +============+---------------+
#  |  1         |  Banana Man    |           ! 2          | 20-MAY-1991   |
#  |  2         |  Satsuma Girl  |           +------------+---------------+
#  +------------+----------------+
#                                  1    0..1 +------------+
#                                  <-------> | DobUnknown |
#                                            +------------+
#                                            |  PersonID  |
#                                            +============+
#                                            | 1          |
#                                            +------------+

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

Конечно, это несколько теоретический. Состояние SQL в эти дни все еще недостаточно продвигается для обработки всего этого. Презентация Хью охватывает эти недостатки. Одна вещь, которую он упоминает, не совсем правильно: некоторые ароматы SQL поддерживают несколько назначение - например, Oracle's Вставьте весь синтаксис.

Другие советы

Я рекомендую вам пойти на свой вариант 2. Я довольно определенную дату Криса тоже потому, что по сути, что вы делаете, полностью нормализуют 6НФ, максимально возможная нормальная форма, которая Дата была совместно ответственна за внедрениеОтказ Я второй рекомендуется Дарванская бумага на обработку отсутствующей информации.

Поскольку внешние соединения не будут допущены (потому что они будут вводить NULL в набор результатов), все необходимые данные могут больше не быть выявлены только с одним запросом, как раньше.

... Это не так, но я согласен, что вопрос внешнего соединения не указан в документе Дарвена; Это было то, что оставило меня, желая. Явный ответ можно найти в другой книге на дату ...

Во-первых, обратите внимание, что дата и собственный по-настоящему реляционный язык Дарвена Учебник D. Есть ли один тип соединения, являющийся естественным присоединением. Обоснование заключается в том, что на самом деле необходимо только один тип соединения.

Дата, которую я ссылался, это отлично SQL и реляционная теория: как написать точный код SQL:

4.6: замечание на внешнем соединении: «реляционно говоря, [внешнее соединение] - вид брака дробовика: он заставляет таблицы в своего рода союз - да, я имею в виду союз, не присоединиться, даже когда таблицы в вопросе не Соответствуйте обычным требованиям для профсоюза ... Это делает это, по сути, наполнение одного или обеих таблиц с нулями, прежде чем делать союз, тем самым заставляя их соответствовать этим обычным требованиям в конце концов. Но нет причин, почему этот прокладки не следует делать с надлежащими ценностями вместо нулевых

Используя свой пример и значение по умолчанию «1900-01-01», как «прокладка», альтернатива внешнему соединению может выглядеть так:

SELECT p.PersonID, p.Name, b.DateOfBirth
  FROM Person AS p
       INNER JOIN BirthDate AS b
          ON p.PersonID = b.PersonID
UNION
SELECT p.PersonID, p.Name, '1900-01-01' AS DateOfBirth
  FROM Person AS p
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM BirthDate AS b
                    WHERE p.PersonID = b.PersonID
                  );

Бумага Дарвена проводится два явных стола, скажем, BirthDate и BirthDateKnown, но SQL не будет сильно отличаться, например, полуприсоединение BirthDateKnown на месте полугодии полу BirthDate над.

Обратите внимание на используемые выше JOIN и INNER JOIN только потому, что стандартный SQL-92 NATURAL JOIN и UNION CORRESPONDING Не существуют широко реализованы в реальных продуктах SQL Real Life (не могут найти цитату, но IIRC DARWEN был в значительной степени ответственны за последние два, которые делают его в стандарт).

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

Person JOIN BirthDate UNION Person NOT MATCHING BirthDate ADD '1900-01-01' AS DateOfBirth;

Я этого не читал, но есть артикула Как обрабатывать недостающую информацию, используя S-BY-C на то Третье манифест Сайт, который работает от Hugh Darwen и CJ Date. Это не написано датой CJ, но я предполагаю, что, поскольку это одна из статей на этом сайте, это, вероятно, похоже на его мнения.

Одна альтернатива может быть ценность атрибута модель:

 entity  attribute    value
 1       name         Banana Man
 1       birthdate    1968-06-20

Если рождение было неизвестно, вы бы просто опустили свою строку.

Вариант 3: ONUS на записи писателя:

CREATE TABLE Person
(
  PersonId int PRIMARY KEY IDENTITY(1,1),
  Name nvarchar(100) NOT NULL,
  DateOfBirth datetime NOT NULL
)

Зачем преобразовать модель, чтобы разрешить NULL представление, когда ваша цель - устранить их?

Вы можете устранить null на выходе, а также с использованием COALESCE.

SELECT personid  /*primary key, will never be null here*/
       , COALESCE(name, 'no name') as name
       , COALESCE(birthdate,'no date') as birthdate
FROM people

Не все базы данных поддерживают Coalesce, но почти все имеют ответный вариант
IFNULL(arg1, arg2) или что-то симпатичное, которое сделает то же самое (но только для 2 аргументов).

Один вариант - использовать явную Опции типов, аналогичный Haskell's Maybe функтор.

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

Это восстанавливает своего рода «нулевой» только для тех атрибутов, где вы явно спрашиваете об этом, но без nullглупо трехценная логика. Nothing == Nothing является True, нет unknown или null.

Поддержка пользовательских алгебраических типов также помогает, когда существует несколько причин отсутствующей информации, например, в базе данных, эквивалентной следующего типа HASKELL, будет хорошим решением для очевидной приложения:

data EmploymentStatus = Employed EmployerID | Unemployed | Unknown

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

Короче говоря, я согласен с Apc.'песок OneDaywhenОтветы о 6nf.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top