Минимальный набор стандартных таблиц

Виноградов С. А.
18.12.2001 г.


Введение

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

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


Структура данных

Следует отметить, что в SQL-серверах очень много зарезервированных слов, которые нельзя использовать в качестве имен таблиц и полей. Поэтому, желательно добавлять какие-нибудь префиксы к названиям, либо всегда пользоваться специальным синтаксисом (вроде [имя] в MS SQL).

Для описания структуры данных, потребуется три основные таблицы: DataTypes, Tables и Columns. Примерное строение этих таблиц (здесь и далее — синтаксис MS SQL):

create table [DataTypes]
(
    [Id] int not null identity primary key,
    [Parent] int references [DataTypes]([Id]),
    [Name] varchar(120) not null unique,
    [Note] varchar(250),
    [SQLType] varchar(250) not null
)

create table [Tables]
(
    [Id] int not null identity primary key,
    [Name] varchar(120) not null unique,
    [Note] varchar(250),
    [Key] int references [Columns]([Id])
)

create table [Columns]
(
    [Id] int not null identity primary key,
    [Table] int not null references [Tables]([Id]),
    [Name] varchar(120) not null,
    [Note] varchar(250),
    [DataType] int not null references [DataTypes]([Id]),
    [Size] int not null,
    [LinkTable] int references [Tables]([Id]),
    [Default] varchar(250),
    [Obligatory] bit not null defaul(0),
    [Unique] bit not null defaul(0)
)

DataTypes хранит названия и описания всех типов данных, используемых в базе. Она должна содержать не только основные типы, но и дополнительные: автонумеруемое поле (Identity), ссылка (поле, содержащее значение ПК другой таблицы) и т.п. Поле Parent позволяет показать наследование одного типа от другого.

Tables содержит имена и описания всех таблиц базы. Key определяет поле, являющееся первичным ключом каждой таблицы.

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

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


Пользователи

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

Для описания пользователей понадобится две таблицы: People и Users.

create table [People]
(
    [Id] int not null identity primary key,
    [LastName] varchar(120) not null,
    [FirstName] varchar(120) not null,
    [MiddleName] varchar(120) not null,
    [Note] varchar(250)
)

create table [Users]
(
    [Id] int not null identity primary key,
    [Name] varchar(120) not null unique,
    [Note] varchar(250),
    [Person] int references [People]([Id])
)

Одному человеку может соответствовать как несколько пользователей, так и ни одного. Но пользователь может быть и виртуальным.

Пользователь может включаться в несколько групп (в общем случае), поэтому понадобится еще две таблицы: Groups и UsersInGroups.

create table [Groups]
(
    [Id] int not null identity primary key,
    [Name] varchar(120) not null unique,
    [Note] varchar(250)
)

create table [UsersInGroups]
(
    [Group] int not null references [Groups]([Id]),
    [User] int not null references [Users]([Id])
    constraint [UserInGroup] primary key ([Group], [User])
)

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


Журнал изменений

Часто бывает нужно организовать хранение истории изменений записей, с возможностью просмотра и отката этих изменений. Таблицы истории обычно достигают большого размера, а используются достаточно редко, поэтому их можно держать в другой базе. Так как изменения происходят в транзакциях, то для их хранения потребуется две таблицы: Transactions и Changes.

create table [Transactions]
(
    [Id] int not null identity primary key,
    [Date] datetime not null default(getdate()),
    [User] int not null references [User]([Id])
)

create table [Changes]
(
    [Id] int not null identity primary key,
    [Transaction] int not null references [Transactions]([Id]),
    [Entity] int not null,
    [Column] int not null references [Columns]([Id]),
    [OldValue] varchar(4000)
)

Transactions хранит дату транзакции и Id пользователя, совершившего ее.

Changes, кроме транзакции, содержит значение ПК изменяемой записи, ссылку на изменяемое поле и прежнее значение поля, преобразованное в строку.

При необходимости, можно добавить возможность записи в журнал историю добавления и удаления записей.

Запись в журнал можно делать либо триггерами, либо из приложения.

Откат изменений следует производить специальной процедурой, которая должна восстановить значения полей для заданной транзакции и удалить соответствующие записи из журнала.


Перечисления

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

create table [Enumerations]
(
    [Id] int not null identity primary key,
    [Parent] int references [Enumerations]([Id]),
    [Code] varchar(120) not null unique,
    [Name] varchar(120) not null
)

Поле Code может являться как кодом целого набора, так и кодом значения в наборе.
Более подробно такая структура описана в статье [1].


Параметры

Довольно часто возникает необходимость держать в базе значения каких-либо глобальных параметров, постоянных или не очень. Например, пути к другим базам/серверам, имена административных файлов, величины процентов налогов и т.п.

Для хранения значений параметров, разбитых по категориям, потребуется таблица Parameters:

create table [Parameters]
(
    [Id] int not null identity primary key,
    [Category] int not null references [Enumerations]([Id]),
    [Name] varchar(120) not null unique,
    [DataType] int not null references [DataTypes]([Id]),
    [Value] varchar(4000)
)


Сообщения

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

create table [Messages]
(
    [Id] int not null identity primary key,
    [Category] int not null references [Enumerations]([Id]),
    [Name] varchar(120) not null unique,
    [Text] varchar(4000)
)

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


Заключение

В завершение можно еще раз перечислить все таблицы, которые потребовались для системного каталога:

Структура данных

Пользователи

Журнал изменений

Перечисления

Параметры

Сообщения



Литература

  1. Виноградов С. А. «Перечисляемый тип в базе данных».



© 2001 Сергей Виноградов
Hosted by uCoz