Продолжаем.
Откуда есть пошла реляционная модель.Далеко в теорию углубляться не будем. Существует множество замечательных книг, лучше которых я точно не напишу, а вот общую идею (практические аспекты в основном) изложить попробую.
Допустим, у нас есть телефонная книга:
Код:
Имя Город Телефон
--------------------------------------------------
Вася Москва 1234567, 5643218
Петя Нью-Васюки 9876543, 5616864, 5168646
Маша Москва 5754566, 6468464
Катя Нью-Васюки 9895757
Проблема этой таблицы в том, что в ней в некоторых ячейках находятся неатомарные значения. В статье "Первая нормальная форма" в Википедии вы можете прочитать, что "концепция «атомарности» является слишком неясной". Что есть, то есть, однако как-то атомизировать значения все равно придется. Это самое плохо формализуемое место в теории, потому что является ли значение атомарным или нет, зависит от задачи и от того, что вы собираетесь делать с вашими данными. Самые большие проблемы возникают со строками. С числами и датами проще, одно число - это одно атомарное значение в 99,99% случаев. В данном случае наша задача состоит в построении телефонной книги, поэтому отдельный телефонный номер представляет отдельную "единицу хранения". Можно исходить из следующих соображений: если вам надо позвонить человеку, вы будете извлекать из БД один номер за раз и звонить на него (а не на все номера через запятую сразу); если вам кто-то позвонил, то с какого-то одного номера за раз, и искать этот номер в БД должно быть проще по полному совпадению строки, а не делать поиск подстроки в строке для каждой ячейки.
Соответственно, надо таблицу переписать так, чтобы в каждой ячейке было атомарное значение:
Код:
Имя Город Телефон
--------------------------------------------------
Вася Москва 1234567
Вася Москва 5643218
Петя Нью-Васюки 9876543
Петя Нью-Васюки 5616864
Петя Нью-Васюки 5168646
Маша Москва 5754566
Маша Москва 6468464
Катя Нью-Васюки 9895757
Теперь у нас следующая проблема. Допустим, мы решили, что Вася - это не солидно, и надо записать его как "Василий Иванович". Но так как у нас несколько записей с таким именем, надо обновлять все. Недостатки такого способа хранения очевидны: фактически, у нас хранится избыточная информация, которую к тому же легко "испортить" (одного "Васю" заменить на "Василия Ивановича", а второго забыть). Тогда мы разбиваем табличку на две:
Код:
Имя Телефон
------------------
Вася 1234567
Вася 5643218
Петя 9876543
Петя 5616864
Петя 5168646
Маша 5754566
Маша 6468464
Катя 9895757
Имя Город
--------------------
Вася Москва
Петя Нью-Васюки
Маша Москва
Катя Нью-Васюки
Вторая табличка является основной для имен, а первая только ссылается на вторую, то есть как бы говорит - "Это телефон вон той Кати из Нью-Васюков".
Далее у нас может возникнуть следующая проблема. В какой-то момент телефонная книга разрастется так, что там окажутся два Васи. Или даже два Василия Ивановича. Как их отличать? Можно добавить дату рождения. Или паспортные данные (если повезет их раздобыть). Самый простой способ - придумать какой-то простой числовой идентификатор (просто порядковый номер), и всех пересчитать. И телефоны заодно пересчитать:
Код:
ID Имя Город
-----------------------
1 Вася Москва
2 Петя Нью-Васюки
3 Маша Москва
4 Катя Нью-Васюки
ID Имя Телефон
------------------------
1 Вася 1234567
2 Вася 5643218
3 Петя 9876543
4 Петя 5616864
5 Петя 5168646
6 Маша 5754566
7 Маша 6468464
8 Катя 9895757
Кроме того, из первой из этих таблиц можно выделить еще одну таблицу с городами, а в таблице с именами оставить просто ссылку на номер города:
Код:
ID Город
-----------------------
1 Москва
2 Нью-Васюки
ID Имя ID Города
-----------------------
1 Вася 1
2 Петя 2
3 Маша 1
4 Катя 2
И с телефонами ту же замену проделать:
Код:
ID ID человека Телефон
------------------------
1 1 1234567
2 1 5643218
3 2 9876543
4 2 5616864
5 2 5168646
6 3 5754566
7 3 6468464
8 4 9895757
Немножко терминологии (для тех, кто решит подтянуть теорию до приемлемого уровня). Чисто теоретические понятия, которые за пределами книг по теории почти не встречаются:
Отношение - таблица
Кортеж - строка таблицы
Атрибут - столбец таблицы
Потенциальный ключ - атрибут или несколько атрибутов, позволяющие однозначно определить строку в таблице. Возможна ситуация, когда сущестует несколько разных потенциальных ключей.
Первичный ключ - один из потенциальных ключей, выбранных в качестве основного.
Нормальные формы - свойства
таблиц отношений, характеризующие степень избыточности. Существуют в количестве аж восьми штук (с номерами с первой по шестую, а третья и пятая имеют подформы без номеров). На практике достаточно уметь отличать третью форму от более низших
, а так же вовремя останавливаться. Обозначаются 1НФ, 2НФ, 3НФ...
В примерах выше: первая табличка не соответствует никакой нормальной форме, вторая - соответствует первой нормальной форме, третья - соответствует третьей нормальной форме. (Вторую я проскочил, потому что так проще и короче).
Понятия чуть ближе к практике:
Естественный ключ - потенциальный ключ, состоящий только из "ествественных" данных (например, ФИО и дата рождения в случае человека в нашем примере).
Суррогатный ключ - искусственно придуманный ключ, значения которого не имеют практического смысла за пределами базы данных (порядковые номера ID в последних примерах). Естественный ключ и суррогатный ключ - это понятия не столько из реляционной теории, сколько из практики ее применения. Никаких теоретических преимуществ у суррогатных ключей нет, это чисто практическая штука.
Справочник - простая таблица, имеющая часто всего два столбца - ID (суррогатный ключ) и какое-нибудь значение. Пример - таблица со списком городов в последнем примере.
Master-Detail (не имеет устоявшегося перевода) - две связанных таблицы, одна "главная", другая - "подчиненная". В примере выше, список людей - это "master", список телефонов - "detail". Detail как бы дает более подробную (детальную) информацию.
Немного ближе к практикеВыше мы разбили одну табличку на две (пример 3) и успокоились. В теории этого достаточно (кажется), но на практике теперь надо следить, чтобы, например, если Васю переименуют в одной таблице, то он переименовался и во второй (а проще, конечно, не менять ни там, ни там). Или чтобы в список телефонов не добавили телефон несуществующего человека. Для этого (но не только) есть такая вещь, как ограничения целостности (см. стартовый пост).
Какие ограничения бывают:
1. Ограничение уникальности. Как мы помним, для однозначной идентификации записи нужен первичный ключ, а первичный ключ должен содержать уникальные значения.
2. Внешний ключ. Если у нас есть две связанные таблицы (как в примере выше), можно (и даже нужно) запретить записывать телефон несуществующего человека (ввиду полной бессмысленности этого действия).
3. NOT NULL. Ограничение запрещает принимать значение NULL, то есть значение всегда должно быть известно и заполнено.
4. Первичный ключ. Фактически, комбинация уникальности и NOT NULL.
5. Ограничения на значения данных в столбце. Например, "нельзя указывать отрицательное число", значение строки может быть только "Да", "Нет" и "Не знаю", и т. п.
Вот теперь можно начинать создавать таблицы и заполнять их данными.