Введение в базы данных
1.1.4 Схема базы, данные и метаданные
Вспомним, что схема записи это описание ее структуры.
Описание базы или ее фрагмента принято называть схемой базы/фрагмента. Некоторые наборы записей в схеме базы могут быть связаны. Поэтому в схему базы включаются ещё связи, представляемые как часть схем связываемых записей, либо отдельным описанием.
Пример: два набора записей — "сотрудник" и "отдел" со следующими схемами:
- сотрудник (табельный_номер, фио, должность, таб_ном_началь-ника, зарплата, комиссионные, номер_отдела),
- отдел ( номер_отдела, название_отдела, город).
Может быть, вам показалось странным объединение слов многословного имени с помощью символа подчёркивания, например "номер_отдела". Это делается для того, чтобы любое имя представлялось последовательностью символов, не разрываемой пробелами. Так удобнее выделять имена. Свяжем эти наборы записей через поля "номер_отдела", имея в виду, что у каждого сотрудника в поле "номер_отдела" должен стоять номер отдела, который имеется в одной из записей набора "отдел" и не может быть номера, не указанного в одной из записей набора "отдел". Остается добавить схему связи:
связь_сотр_отд(сотрудник. номер_отдела, отдел. номер_отдела)
Точечный синтаксис в именах позволяет связать несколько уровней представления данных. Если необходимо указать поле "номер_отдела" из набора "сотрудник", пишем "сотрудник.номер_отдела".
Для практического использования приведенной схемы следовало бы уточнить многие подробности. Например, как-то указать, что в отделе может не быть сотрудников, что один сотрудник не может работать в двух отделах и т.д. Сейчас мы не будем заниматься такими деталями.
Рассмотрим теперь метаданные, то есть данные специального вида, которые описывают структурные свойства хранимых данных, то есть схему базы. Какие-то метаданные имеются всегда, и потому база всегда обладает свойством самодокументируемости, более или менее выраженным. В реализациях к базе данных, хранящей основные данные, обычно добавляют вторую базу (словарь, репозитарий), которая хранит метаданные.
Понятно, что метаданные — это некоторая существенная часть семантики базы, но не вся семантика. Рассмотрим в качестве примера базу данных, в которой наборы записей представляются как таблицы. Содержимое одной из них —Т1 — показано в таблице 1.1. Предполагается, что в схеме существуют и другие таблицы, например Т2, не показанная на рисунках.
ФИО | Адрес | Телефон |
Иванов И.И. | Ставропольская, 149 | 1-111-111 |
Петров П.П. | Ставропольская, 153 | 2-222-222 |
Часть метаданных записана в двух таблицах. Ml содержит перечень таблиц, М2 —перечень столбцов (таблица 1.2, таблица 1.3). Если метаданные имеются, появляется возможность перед выполнением любого действия проверить правильность его записи (синтаксиса). Можно узнать, существуют ли таблицы, к которым обращаются, правильно ли названы столбцы и т.д.
И поскольку метаданные записываются в базе и активны, то их можно считать разновидностью смыслов, которые упоминались в разделе 1.1.1.
НОМЕР | ТАБЛИЦЫ | НОМЕРСТОЛБЦА | ИМЯСТОЛБЦА | |
1 | 1 | ФИО | ||
1 | 2 | Адрес | ||
1 | 3 | Телефон | ||
2 | 1 | Назв отдела |
1.2 Модели данных. Базы данных и файловые системы.
1.2.1 Ограничения целостности
Ограничения целостности —это условия специального вида, которые должны выполняться для поля, или для записи (или другой основной структуры данных), или для набора записей, или для некоторой подсхемы базы данных, или для всей схемы базы. Используется условное разделение ограничений на декларативные и процедурные.
Декларативными называют ограничения, которые в используемом языке определения структур данных могут быть выражены специальной фразой языка. Например, ограничение "первичный ключ" обычно обозначается фразой с ключевыми словами PRIMARY KEY (сокращенно PK), которая приписывается к описанию поля или оформляется в отдельно записываемое ограничение целостности.
Процедурные ограничения обычно определяются заданием процедур специального вида, называемых триггерами.
Примеры декларативных ограничений целостности:
- Ограничение "Первичный ключ". Если имеем дело только с людьми, у которых есть ИНН, то в наборе записей со схемой Сотрудник (ИНН, ФИО, Должность, Зарплата)
- поле "ИНН" может использоваться как первичный ключ.
- Ограничение "Проверка" (Check).
В наборе записей со схемой Сотрудник (ИНН, ФИО, Должность, Зарплата, Бонус) для каждой записи должно выполняться условие Бонус < 0.2 * Зарплата
Замечание. Ограничения типа Check строятся на данных одной записи.
Пример процедурного ограничения целостности: В наборе записей из последнего примера предусмотрим возможность изменения поля "Зарплата" только в сторону уменьшения.
Почему это ограничение не декларативно? Потому, что назначаемая зарплата в базе данных пока еще не записана и отношение "Новая_зарплата" < "Старая_зарплата" нельзя выразить через данные, имеющиеся в базе.
Замечание. Поддержание любых ограничений целостности требует активности базы и реализуется процедурами, работающими подобно резидентным программам. Они запускаются по наступлении некоторого события. В простейшем случае это события ввода, обновления и удаления записи.
1.2.2 Неопределенные значения (NULL)
Необходимость введения неопределённых значений и возникающие при этом проблемы рассмотрим на примере. Пусть имеется набор записей о сотрудниках некоторой организации, где указаны уникальный табельный номер, фамилия, должность, размер заработной платы и получаемые комиссионные. Особенность в том, что комиссионные могут получать только продавцы. Остальным работникам комиссионные не положены. Ничего страшного. В графу комиссионные для них пишем нуль. И вот тут начинаются проблемы. Как, анализируя поле, отличить работника, которому комиссионные не положены, от работника, которому они положены, но он их не заработал (значение тоже 0). Как вычислить среднее значение комиссионных? Делить сумму комиссионных следовало бы не на число всех работников, а только тех работников, которым комиссионные положены.
Можно в рамках типа данных придумать особые значения для указания на то, что значение отсутствует. В нашем примере можно было бы, скажем, для тех, кому не положены комиссионные, записывать значение — 1 и, анализируя его, отбрасывать строки, содержащие —1, при подсчёте средних комиссионных. Но такой подход не универсален. Если поле допускает отрицательные значения, придется придумать какое-то другое выделенное значение.
Можно к полю с возможными неопределёнными значениями прикрепить вспомогательное поле, в набор значений которого входит и неопределённость значения и масса других вариантов смысла. Например, можно было бы отличать "не определено" от "не известно".
Большинство современных баз данных, работающих с записями, пошли по другому пути. Вводится определитель NULL, обозначающий отсутствие какого-нибудь значения. NULL не зависит от типа данных и не принадлежит никакому типу. Вместе с тем символ NULL можно записывать в любое поле. Возникающие при этом проблемы будут частично рассмотрены в следующих лекциях.
Помните, что пустое значение (число 0 или пустая строка), часто задаваемое по умолчанию — это не NULL.
Любые алгебраические операции (сложение, умножение, конкатенация строк и т.д.) с операндом NULL должны давать также неопределенное значение NULL. В самом деле, какое значение может иметь, например, NULL+7? Только неопределенное.
Неопределенные значения существуют в любых моделях данных. Их нет в языках программирования общего назначения. Не путайте NULL с пустыми ссылками в этих языках.
При обработке данных с неопределенными значениями кроме значений истинности "Истинно" и "Ложно" может получиться ещё значение "Не известно". Поэтому при обработке данных необходимо воспользоваться вариантом трехзначной логики с перечисленными значениями истинности.
Таблицы истинности для этой трехзначной логики приведены в таблицах 1.4, 1.5, 1.6.
Значения истинности Т-ИСТИНА (TRUE), F-ЛОЖЬ (FALSE), U-НЕИЗВЕСТНО (UNDEFINED). Логическое значение U соответствует пустому значению.
Если вам трудно запомнить таблицы истинности трёхзначной логики, используйте отображение , , и интерпретируйте функции AND, OR, NOT через min, max и 1 — X, соответственно.
Поскольку NULL не входит ни в один из типов данных, для работы с ним вводятся специальные операции. Так, для сравнения с NULL используют не равенство, а операцию "is". Перечислим некоторые её особенности:
- NULL is NULL имеет значение истинности U, а не Т;
- NULL is not NULL также принимает значение U, а не F;
- если А принимает значение NULL, то значение выражения A OR (NOT А) не истинно, а не определено.
Заметим, что в СУБД могут использоваться другие интерпретации неопределённых значений и операций над ними. Обязательно проверьте перечисленные условия при изучении языка SQL в Cache и Oracle.
Как уже сказано, в языках программирования общего назначения неопределенные значения отсутствуют. Поэтому переменная Y, принимающая в базе значение NULL, обычно передается в этих языках двумя переменными Y и YInd. Если Y принимает определенное значение, то значение индикатора YInd равно 0, и можно работать с Y. Если же Y принимает неопределенное значение, то YInd = 1, а значение Y использовать нельзя.
В итоге получается довольно странная картина. Троичная логика непосредственно не используется, но в процедурной части приложения, работающего с неопределёнными значениями, появляются разветвления на три стороны (ветви по "Да", по "Нет" и по "Не определено"), а не на две, как обычно.