Общая методика нормализации БД

Одной из проблем разработки БД является проблема группировки данных в БД. Существует много способов группировки элементов данных; одни из них лучше, другие — хуже, а третьи могут привести к сложным проблемам.

Большинство БД непрерывно изменяется. Добавляются новые элементы данных, между ними устанавливаются новые связи и определяются новые способы их использования. При изменении БД необходимо сохранять старое представление пользователя о данных для того, чтобы избежать необходимости переписывать старые программы заново. Однако возможны и такие изменения связей между данными, которые требуют модификации программ. Например, иногда оказывается необходимым расщепить запись или сегмент на две части, или же изменить ключ некоторых элементов. Изменения такого рода являются крайне нежелательными, т.к. могут привести к разрушению структуры БД. В то же время такие разрушения можно сделать маловероятными, если группировка элементов данных и их ключи первоначально были хорошо продуманы.

Рассматриваемая методика рациональной группировки элементов данных, называемая нормализацией БД, является наиболее распространенной основой разработки структур БД, минимизирующей вероятность их разрушения.

Нормализация — это формальный аппарат ограничений на формирование таблиц, устраняющий дублирование, обеспечивающий непротиворечивость хранимых данных и уменьшающий трудозатраты на ведение БД.

Процесс нормализации заключается в разложении (декомпозиции) исходных отношений БД на более простые. При этом на каждой ступени этого процесса схемы отношений приводятся к нормальным формам. Для каждой ступени нормализации имеются наборы ограничений, которым должны удовлетворять отношения БД. Процесс нормализации имеет своей целью устранение избыточности данных и заключается в последовательном приведении БД к третьей нормальной форме (ЗНФ).

Первая нормальная форма (1НФ) требует, чтобы каждое поле таблицы БД было неделимым и не содержало повторяющихся групп.

Неделимость поля означает, что содержащиеся в нем значения не должны делиться на более мелкие поля. Например, если в поле «Подразделение» содержится название факультета и название кафедры, требование неделимости не соблюдается и необходимо выделить название факультета или кафедры в отдельное поле; поле, содержащее Фамилию, имя и отчество, следует разделить на три поля — отдельно для фамилии, имени и отчества и т.д.

Повторяющимися являются поля, содержащие одинаковые по смыслу значения, например, если требуется получить статистику продаж четырех товаров по месяцам, можно создать поля для хранения данных о продаже по каждому товару (Таблица 9.1).

Таблица 9.1.

Статистика продаж
Год Месяц Товар 1 Товар 2 Товар 3 Товар 4

Однако такой подход не годится, если количество товаров заранее не известно. Повторяющиеся группы следует устранить, сохранив в таблице единственное поле «Товар» (Таблица 9.2.) В результате получим запись, содержащую информацию о статистике продаж по одному товару, но этот товар может быть любым: для 4 товаров будем иметь 4 записи, для 104 товаров — 104 записи и т д.

Таблица 9.2.

Статистика продаж
Год Месяц Товар

Рассмотрим пример приведения БД к 1НФ. Пусть необходимо автоматизировать процесс отпуска товаров со склада по накладной, примерный вид которой показан в Таблице 9.3.

Таблица 9.3. Накладная

  Накладная 123
Дата Покупатель Адрес
10.01.10 ООО «Кормилец» г. Иркутск, ул. Трактовая, 20
Отпущенный товар Количество Ед. измерения Цена Общая стоимость
Тушенка Сахар Макароны   Банки кг кг    
Итого  
             

Сведем имеющиеся данные в одну таблицу. Приводя ее к 1НФ, учтем, что впоследствии будет необходимо производить анализ продаж по городам. Поэтому из поля «Адрес» (допускающего толкование как делимого поля) выделим часть данных (город) в отдельное поле «Город».

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

Вторая нормальная форма (2НФ) требует, чтобы все поля таблицы зависели от первичного ключа, т.е. чтобы первичный ключ однозначно определял запись и не был избыточен. Поля, которые зависят только от части первичного ключа, должны быть выделены в отдельные таблицы.

Таблица 9.4.

Отпуск товаров со склада
Дата Покупатель Город Адрес Товар Ед_измерения Цена_за_ед_измерения Отпущено_ед Общая_стоимость №_накладной

Для приведения к 2НФ выделим поля, которые входят в первичный ключ. Дата накладной и номер накладной по отдельности не могут уникально определять запись, поскольку они будут одинаковы для всех записей, относящихся к одной и той же накладной (напомним, что одна накладная в Таблице 9.4 представляется несколькими записями). Поэтому введем в первичный ключ поле «Товар». При этом исходим из предположения, что по одной накладной может быть отпущено одно наименование конкретного товара, т.е. не может быть ситуации, когда отпуск одного и того же товара оформляется в накладной двумя строками, что повлекло бы за собой две одинаковые записи в таблице «Отпуск товаров со склада».

Таблица 9.5.

Отпуск товаров со склада
Дата Покупатель Товар №_накладной Город Адрес Ед_измерения Цена_за_ед_измерения Отпущено_ед Общая_стоимость

В таблице 9.5. показана структура таблицы после выделения полей сцепленного первичного ключа (эти поля отчеркнуты от прочих полей линией и располагаются в верхней части структуры таблицы). Созданный нами первичный ключ является избыточным: поле «№ накладной» однозначно определяет дату и покупателя. Для данной накладной не может быть никакой иной даты и никакого иного покупателя. Поле «Товар» в комбинации с № накладной, напротив, однозначно идентифицирует запись. После устранения избыточности первичного ключа получаем Таблицу 9.6.

Таблица 9.6.

Отпуск товаров со склада
Товар №_накладной Дата Покупатель Город Адрес Ед_измерения Цена_за_ед_измерения Отпущено_ед Общая_стоимость

Первое требование 2НФ выполнено, чего не скажешь о втором, гласящем, что значения всех полей записи должны однозначно зависеть от совокупного значения первичного ключа и не должна иметь место ситуация, когда некоторые поля зависят от части первичного ключа. В Таблице 9.6 поля «Единица измерения», «Цена за единицу измерения» зависят от значения поля «Товар», входящего в первичный ключ. Поэтому выделяем эти поля в самостоятельную таблицу «Товары» и определяем связь: поскольку один товар может присутствовать во многих накладных, таблицы «Товары» и «Отпуск товаров со склада» находятся в связи 1:М (рис. 9.1).

Рис. 9.1

Можно заметить, что теперь значение поля «Покупатель» никоим образом не зависит от пары значений «№ накладной», «Товар», а «зависит только от значения поля «№ накладной». Поэтому данное поле и зависящие от его значения поля «Город», «Адрес» выделяем в таблицу «Покупатели».
Анализируя далее структуру таблицы «Отпуск товаров со склада», обнаруживаем, что одно из оставшихся полей — «Дата» — зависит только от значения поля «№ накладной». Поэтому выделяем дату и номер накладной в самостоятельную таблицу «Накладные» (рис. 9.2).

Рис. 9.2.

Установим связи между таблицами. Один покупатель может встречаться во многих накладных. Поэтому между таблицами «Покупатели» и «Накладные» имеется связь 1:М по полю «Покупатель». Одной накладной может соответствовать несколько товаров. Поэтому между таблицами «Накладные» и «Отпуск товаров со склада» имеется связь 1:М по полю «№ накладной» (рис. 9.3).

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

Рис. 9.3. БД во 2-й нормальной форме

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

В рассматриваемом примере можно увидеть, что в таблице «Отпуск товаров со склада» имеется зависимость значения поля «Общая стоимость» от значения поля количество т. е. «Отпущено_ед». По условию примера значение поля «Общая стоимость» может вычисляться как значение поля «Отпущено_ед», умноженное на значение поля «Цена за единицу измерения» из таблицы «Товары» (из записи с таким же значением поля «Товар»). Поэтому поле «Общая стоимость» из таблицы «Отпуск товаров со склада» удаляем.

Однако в случае, если «Цена за единицу измерения» зависит от количества отпущенного товара, что особенно распространено в наше рыночное время, следует создать отдельную таблицу, отображающую зависимость цены от количества отпущенного товара, после чего будет получена БД в 3НФ.

Замечание. В таблице «Покупатели» значение поля «Адрес» зависит от значения поля «Город», поскольку в разных городах могут оказаться улицы с одинаковыми названиями и, соответственно, дома с одинаковыми номерами (вспомним известный кинофильм «Ирония судьбы, или с легким паром»). Однако такой зависимостью можно пренебречь, поскольку поле «Адрес» в нашем случае носит чисто информационный характер и не должно входить в условия запросов самостоятельно. Вообще говоря, на практике не всегда возможно получить идеально нормализованную БД, да и не всегда это необходимо, т. е. бывает достаточно 2-й нормальной формы.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: