Что такое база данных?

Элементы базы данных Access

Базовые тезисы

Прежде всего необходимо сформулировать
основные принципы, на которых будет
строиться проектируемая БД.

  1. Каждая сущность, информация о которой хранится в БД, — это объект.
  2. Каждый объект уникален в пределах БД и имеет уникальный идентификатор.
  3. Объект имеет свойства (строковые, числовые, временные, перечислимые), которые
    описывают атрибуты сущности.
  4. Объекты могут быть связаны между собой произвольным образом. Связь характеризуется
    связанными объектами и типом связи. Например, сотрудник фирмы может быть связан
    с отделом, в котором он работает, связью типа «сотрудник в отделе» и т.п.
    Связь в определенном смысле аналогична понятию ссылки на таблицу-справочник
    в традиционной модели БД.
  5. Объект может быть хранилищем. В этом случае допускается хранение в нем других
    объектов (например, товара на складе).

Такая БД не привязана ни к какой бизнес-модели и позволяет реализовать «над
собой» практически любую бизнес-логику. Логика выделяется в отдельный программный
слой и, как правило, реализуется на сервере приложений, где по запросу клиента
создаются объекты, загружающие информацию о себе из БД и реализующие «поведение»
объектов реального мира.

Что представляет собой база данных?

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

Информация, отображенная в виде списка, становится непонятной. Кроме того, ограничены способы, с помощью которых можно искать и отображать подмножества данных. Как только начинают появляться эти проблемы, мы рекомендуем перенести всю информацию в базу данных, созданную в системе управления базами данных (СУБД), такой как Access.

Что относится к объектам базы данных

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

Для файлов баз данных, созданных в формате Access 2007 (который также используется в Access 2016, Access 2013 и Access 2010), используется расширение ACCDB, а для баз данных, созданных в более ранних версиях Access, — MDB. С помощью Access 2016, Access 2013, Access 2010 и Access 2007 можно создавать файлы в форматах более ранних версий приложения (например, Access 2000 и Access 2002–2003).

Использование Access позволяет:

  • добавлять новую информацию в базу данных, например новый артикул складских запасов;

  • изменять информацию, уже находящуюся в базе, например перемещать артикул;

  • удалять информацию, например если артикул был продан или утилизирован;

  • упорядочивать и просматривать данные различными способами;

  • обмениваться данными с другими людьми с помощью отчетов, сообщений электронной почты, внутренней сети или Интернета.

Объекты

Большинство баз данных содержат несколько разных типов объектов, например,
таблицы для хранения данных, индексы для сортировки данных и поддержки ключей,
ограничения или правила (constraints, rules) для поддержки ссылочной целостности
и ограничения значений данных, триггеры (triggers) и хранимые процедуры (stored
procedures) для хранения исполняемого кода.

Таблицы и поля

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

Индексы

Чуть выше мы говорили о роли первичных
и внешних ключей. В большинстве реляционных СУБД
ключи реализуются с помощью объектов, называемых
индексами,
которые можно определить как список номеров
записей, указывающий, в каком порядке их
предоставлять.

https://www.youtube.com/watch?v=ytcopyrightru

Мы уже знаем, что записи в реляционных
таблицах неупорядочены. Тем не менее любая
запись в конкретный момент времени имеет вполне
определенное физическое местоположение в файле
базы данных, хотя оно и может изменяться в
процессе редактирования данных или в результате
«внутренней деятельности» самой СУБД.

Предположим, в какой-то момент времени записи в таблице Customers хранились
в таком порядке.

1,6,4,2,5,3
5,4,1,6,2,3

Хранение индексов требует существенно
меньше места, чем хранение по-разному
отсортированных версий самой таблицы.

Если нам нужно найти данные о клиентах,
у которых CustomerID
начинается с символов «BO», мы можем найти с помощью индекса
местоположение этих записей (в данном случае 2 и 5
(очевидно, что в индексе номера этих записей идут
подряд), а затем прочесть именно вторую и пятую
записи, вместо того чтобы просматривать всю
таблицу. Таким образом, использование индексов
снижает время выборки данных.

Мы уже говорили о том, что физическое местоположение записей может изменяться
в процессе редактирования данных пользователями, а также в результате манипуляций
с файлами базы данных, проводимых самой СУБД (например, сжатие данных, сборка
«мусора» и др.). Если при этом происходят соответствующие изменения и в индексе,
он называется поддерживаемым и такие индексы используются в большинстве
современных СУБД.

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

Большинство современных серверных
СУБД содержат специальные объекты, называемые ограничениями (constraints), или правилами (rules). Эти объекты
содержат сведения об ограничениях,
накладываемых на возможные значения полей.
Например, с помощью такого объекта можно
установить максимальное или минимальное
значение для данного поля, и после этого СУБД не
позволит сохранить в базе данных запись, не
удовлетворяющую данному условию.

Помимо ограничений, связанных с
установкой диапазона изменения данных,
существуют также ссылочные ограничения (referential constraints, например связь
master-detail между таблицами Customers и Orders
может быть реализована как ограничение,
содержащее требование, чтобы значение поля CustomerId (внешний ключ) в
таблице Orders
было равно одному из уже имеющихся значений поля CustomerId таблицы Customers.

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

Представления

Практически все реляционные СУБД
поддерживают представления (views). Этот объект представляет
собой виртуальную таблицу, предоставляющую
данные из одной или нескольких реальных таблиц.
Реально он не содержит никаких данных, а только
описывает их источник.

Нередко такие объекты создаются для
хранения в базах данных сложных запросов.
Фактически view — это хранимый запрос.

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

Нередко эти объекты используются для обеспечения безопасности данных, например,
путем разрешения просмотра данных с их помощью без предоставления доступа непосредственно
к таблицам. Помимо этого некоторые представления объекты могут возвращать разные
данные в зависимости, например, от имени пользователя, что позволяет ему получать
только интересующие его данные.

Триггеры и хранимые процедуры,
поддерживаемые в большинстве современных
серверных СУБД, используются для хранения
исполняемого кода.

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

Хранимые процедуры обычно
используются при выполнении часто встречающихся
задач (например, сведение бухгалтерского
баланса). Они могут иметь аргументы, возвращать
значения, коды ошибок и иногда наборы строк и
колонок (такой набор данных иногда называется
термином dataset).
Однако последний тип процедур поддерживается не
всеми СУБД.

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

Предлагаем ознакомиться  Как проверить патент на сайте ФМС

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

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

В разных СУБД для генерации ключей
используются разные объекты. Некоторые из таких
объектов хранят целое число и правила, по которым
генерируется следующее за ним значение, —обычно
это выполняется с помощью триггеров. Такие
объекты поддерживаются, например, в Oracle (в этом случае они
называются последовательностями — sequences) и в IB Database (в этом случае
они называются генераторами — generators).

Некоторые СУБД поддерживают специальные типы полей для первичных ключей. При
добавлении записей такие поля заполняются автоматически последовательными значениями
(обычно целыми). В случае Microsoft Access и Microsoft SQL Server такие поля
называются Identity fields, а в случае Corel Paradox — автоинкрементными полями
(Autoincrement fields).

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

Предотвращение несанкционированного
доступа к данным является серьезной проблемой,
которая решается разными способами. Самый
простой — это парольная защита либо всей
таблицы, либо некоторых ее полей (такой механизм
поддерживается, например, в Corel Paradox).

ObjType
Id INTEGER Первичный ключ
Code CHAR(10) NOT NULL UNIQUE Краткое название типа. Используется в программе для поиска объектов данного
типа
ItemName CHAR(30) Полное название типа, используется только для интерфейса

Типами объектов могут быть, например, «Фирма»,
«Сотрудник», «Товар».

Для упрощения не будем реализовывать
наследования — отметим лишь, что для этого
необходимо ввести в ObjType
поле ParentId,
ссылающееся на Id
наследника.

Objects
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта
ItemName CHAR(50) Название объекта

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

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

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

SELECT O.Id, O.ItemName, OT.ItemName
   FROM Objects O
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
  WHERE OT.Code = ‘EMPLOYEE’  

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

Свойства

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

https://www.youtube.com/watch?v=ytpolicyandsafetyru

Величина
же может выражаться данными различного
типа. Будем хранить в БД атрибуты следующих
типов:

  • Строковые
  • Числовые. Различия между целыми и вещественными числами делать не будем,
    полагая целые подмножеством вещественных. Если задача диктует невозможность
    применения данного подхода — придется выделять эти атрибуты в различные типы
  • Исторические (дата и время)
  • Перечислимые (например, форма собственности фирмы)

Строковые атрибуты

Для
описания атрибутов заведем таблицу

StrDesc
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта
Code CHAR(10) Краткое название параметра
ItemName CHAR(30) Полное название параметра, используется только для интерфейса

«FAMILY» —
фамилия

«FIRSTNAME»
— имя

«LASTNAME»
— отчество

«ADDRESS» —
адрес

«EMAIL»
— адрес электронной почты

Поле Objects.ItemName для сотрудников заполняется сервером
приложений как комбинация из атрибутов FAMILY FIRSTNAME LASTNAME.

Strings
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES StrDesc(Id) Ссылка на тип параметра
ObjectId INTEGER REFERENCES Objects(Id) Ссылка на объект
Value VARCHAR(255) Значение параметра
SELECT O.ItemName, S.Value
   FROM Objects O
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
    INNER JOIN Strings S ON O.Id = S.ObjectId
    INNER JOIN StrDesc SD ON S.TypeId = SD.Id
  WHERE OT.Code = ‘EMPLOYEE’
    AND SD.TypeId = OT.Id
    AND SD.Code = ‘EMAIL’  
SELECT O.ItemName, S.Value
   FROM Objects O
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
    LEFT JOIN Strings S ON O.Id = S.ObjectId
    LEFT JOIN StrDesc SD ON S.TypeId = SD.Id
  WHERE OT.Code = ‘EMPLOYEE’
    AND SD.TypeId = OT.Id
    AND SD.Code = ‘EMAIL’  

Интересный эффект можно получить, создав
у различных типов объектов атрибуты с
одинаковыми значениями поля Code.
Предположим, что у объектов
типов EMPLOYEE (сотрудник) и FIRM (организация)
есть строковые атрибуты с одинаковым
именем ‘EMAIL’. Тогда можно одним запросом
получить адресную книгу по всем известным в
БД почтовым адресам.

SELECT O.ItemName, OT.ItemName, S.Value
   FROM Objects O
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
    INNER JOIN Strings S ON O.Id = S.ObjectId
    INNER JOIN StrDesc SD ON S.TypeId = SD.Id
  WHERE SD.Code = ‘EMAIL’
 ORDER BY OT.ItemName, O.ItemName  

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

Числовые атрибуты

PropDesc
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта
Code CHAR(10) Краткое название параметра
ItemName CHAR(30) Полное название параметра, используется только для интерфейса
Properties
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES PropDesc(Id) Ссылка на тип параметра
ObjectId INTEGER REFERENCES Objects(Id) Ссылка на объект
Value DECIMAL(20,4) Значение параметра. На серверах, поддерживающих тип данных MONEY (аналог
Currency в Delphi), удобно использовать этот тип

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

Status
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта
Code CHAR(10) Краткое название состояния
ItemName CHAR(30) Полное название состояния, используется только для интерфейса

«WASBORN»
— Дата рождения

«EMPLOYEED» — Принят на работу

«DISMISS»
— Уволен

https://www.youtube.com/watch?v=channelUCChlEuiwrL1LhPtu3AKS98Q

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

History
Id INTEGER Первичный ключ
StatusId INTEGER REFERENCES Status(Id) Ссылка на тип состояния
ObjectId INTEGER REFERENCES Objects(Id) Ссылка на объект
ItemDate DATETIME Дата возникновения состояния
SELECT O.ItemName, H.ItemDate AS Employeed
   FROM Objects O
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
    INNER JOIN History H ON H.ObjectId = O.Id
    INNER JOIN Status S ON H.StatusId = S.Id
 WHERE OT.Code = ‘EMPLOYEE’
   AND S.Code = ‘EMPLOYEED’
   AND H.ItemDate = (SELECT MAX(H1.ItemDate)
                       FROM History H1
                        INNER JOIN Status S1 ON H1.StatusId = S1.Id
                       WHERE H1.ObjectId = O.Id
                         AND H.ItemDate {amp}lt;= :DateParam
                         AND S1.Code IN (‘EMPLOYEED’, ‘DISMISS’))  
EnumDesc
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта
Code CHAR(10) Краткое название состояния
ItemName CHAR(30) Полное название состояния, используется только для интерфейса
EnumValues
Id INTEGER Первичный ключ
DescId INTEGER REFERENCES EnumDesc(Id) Ссылка на тип перечисления
Code CHAR(10) Краткое название значения
ItemName CHAR(30) Полное название значения, используется только для интерфейса
Предлагаем ознакомиться  Кто такие иждивенцы в семье по закону
Enums
Id INTEGER Первичный ключ
ValueId INTEGER REFERENCES EnumValues(Id) Ссылка на значение
ObjectId INTEGER REFERENCES Objects(Id) Ссылка на объект
TypeId Code ItemName
Ссылка на ObjType для типа «FIRM» OWNERFORM Форма собственности
DescId Code ItemName
Ссылка на EnumDesc для ИЧП Индивидуальное частное предприятие
типа «OWNERFORM» ООО Общество с ограниченной ответственностью
   

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

Таблицы

Таблица базы данных похожа на электронную таблицу — и там, и там информация расположена в строках и столбцах. Поэтому импортировать электронную таблицу в таблицу базы данных обычно довольно легко. Основное различие заключается в том, как данные структурированы.

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

Строки в таблице называются записями. В записи содержатся блоки информации. Каждая запись состоит по крайней мере из одного поля. Поля соответствуют столбцам в таблице. Например, в таблице под названием «Сотрудники» в каждой записи находится информация об одном сотруднике, а в каждом поле — отдельная категория информации, например имя, фамилия, адрес и т. д. Поля выделяются под определенные типы данных, например текстовые, цифровые или иные данные.

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

Дополнительные сведения о таблицах см. в статье Общие сведения о таблицах.

Связи

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

LinkType
Id INTEGER Первичный ключ
Code CHAR(10) Краткое название связи
ItemName CHAR(30) Полное название связи, используется только для интерфейса
Links
Id INTEGER Первичный ключ
ParentId INTEGER REFERENCES Objects(Id) Ссылка на первый из связываемых объектов
ChildId INTEGER REFERENCES Objects(Id) Ссылка на второй из связываемых объектов
TypeId INTEGER REFERENCES LinkType(Id) Ссылка на тип связи
SELECT O.ItemName
     FROM Objects O
      INNER JOIN Links L ON O.Id = L.ParentId
      INNER JOIN LinkType LT ON LT.Id = L.TypeId
   WHERE LT.Code = ‘MANAGER’
     AND L.ChildId = :FirmId  -- Первичный ключ объекта-фирмы 
SELECT Employee.ItemName
     FROM Objects Employee
      INNER JOIN Links L ON L.ChildId = Employee.Id
      INNER JOIN LinkType LT ON L.TypeId = LT.Id
      INNER JOIN Objects Departments ON L.ParentId = Departments.Id
      INNER JOIN ObjType OT ON Departments.TypeId = OT.Id
   WHERE OT.Code = ‘DEPARTMENT’
     AND LT.Code = ‘EMPDEPART’
     AND Department.ItemName = ‘Отдел поставок’ 
AllowedLinks
Id INTEGER Первичный ключ
ParentId INTEGER REFERENCES ObjType(Id) Ссылка на тип первого из связываемых объектов
ChildId INTEGER REFERENCES ObjType(Id) Ссылка на тип второго из связываемых объектов
TypeId INTEGER REFERENCES LinkType(Id) Ссылка на тип связи

На вставку и изменение записей в Links
создается несложный триггер, который
проверяет типы объектов для создаваемой
связи и их допустимость по AllowedLinks.
Поскольку разрешенные типы связей хранятся
в таблице, мы получаем гибкий механизм для
настройки БД под требования конкретной
задачи. Если требуется задать новый тип
связи между объектами — достаточно лишь
добавить в AllowedLinks
запись с этим типом связи и типами объектов.

Замечу,
что предлагаемая модель позволяет легко
хранить иерархические данные. Для
этого надо лишь задать связь типа «находится
в».

Выбирая,
какой тип объекта должен быть первым (ParentId),
а какой вторым (ChildId) в связи, рекомендуется
придерживаться единой системы. Для БД это
безразлично, однако для уменьшения
путаницы лучше в качестве первого выбирать
объект, который бы оказался на стороне «один»
отношения «один-ко-многим» при
проектировании БД по классической методике.
Если объекты связаны
по принципу «многие-ко-многим», надо просто
выработать для себя единую методику и в
дальнейшем ей следовать.

Формы

С помощью форм создается пользовательский интерфейс для ввода и редактирования данных. Формы часто содержат кнопки команд и другие элементы управления, предназначенные для выполнения различных функций. Можно создать базу данных, не используя формы, если просто отредактировать уже имеющуюся информацию в таблицах Access. Тем не менее, большинство пользователей предпочитает использовать формы для просмотра, ввода и редактирования информации в таблицах.

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

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

Дополнительные сведения о формах см. в статье Формы.

Расширение БД

https://www.youtube.com/watch?v=ytcreatorsru

Итак,
полученная БД может хранить описание
произвольных сущностей, позволяет
динамически определять и устанавливать
между ними произвольные связи. Для
многих задач (например, отдел кадров), в
которых каждый объект уникален, этого уже
достаточно. Однако существует много задач,
под которые полученное «ядро» было бы
неплохо пополнить дополнительными
возможностями.

Налаживаем учет

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

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

Movement
Id INTEGER Первичный ключ
OperationId INTEGER REFERENCES Objects(Id) Ссылка на объект-операцию, группирующую логически связанные перемещения
ContainerId INTEGER REFERENCES Objects(Id) Ссылка на объект-хранилище, на который совершается приход либо с которого
совершается расход
ContentId INTEGER REFERENCES Objects(Id) Ссылка на объект, который перемещается
Amount DECIMAL(20,4) Количество
ItemDate DATETIME Дата перемещения

Рассмотрим некоторые поля этой таблицы
подробнее.

OperationId

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

  • продажа
    товара — расход товара со склада, приход
    денег в кассу, расход денег с фирмы-покупателя,
    приход товара на фирму-покупатель;

  • конвертация
    — расход одной валюты и приход другой (возможно
    на другой счет);

  • производство
    — расход нескольких товаров со склада
    материалов и приход одного (или
    нескольких же) других товаров на склад
    готовой продукции;

  • бухгалтерская
    проводка — дебет одного счета и кредит
    другого (либо нескольких других).

Предлагаем ознакомиться  Представление нового сотрудника коллективу - Без проблем

ContainerId

Ссылка на объект-хранилище, на который
приходят либо с которого уходят
материальные ценности. Таким объектом
может быть склад, касса, фирма-контрагент и
т.п. Хранилище само может выступать как
перемещаемый объект — например гвозди
лежат в ящике, а ящик лежит на складе.

Amount

Перемещаемое
количество. Если Amount
{amp}gt; 0 — это приход, в противном случае —
расход.

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

SELECT Sum(Amount)
   FROM Movement
 WHERE ContentId = :{amp}lt;Id объекта «рубли»{amp}gt;
   AND ContainerId = :{amp}lt;Id объекта «касса»{amp}gt;
   AND ItemDate {amp}lt;= :InterestDate  
Запрос:  
SELECT O.Id, O.ItemName, SUM(M.Amount)
   FROM Movement M
    INNER JOIN Object O ON M.ContentId = O.Id
    INNER JOIN ObjType OT ON O.TypeId = OT.Id
  WHERE OT.Code = ‘GOOD’
    AND M.Amount {amp}gt; 0
    AND M.ContainerId = :{amp}lt;Id объекта «склад»{amp}gt;
    AND M.ItemDate BETWEEN :StartDate AND :EndDate
 GROUP BY O.Id, O.ItemName  

вернет суммы прихода на склад по всем
товарам (тип объекта «GOOD»)
за период от StartDate
до EndDate.

Истинная
мощь аналитических возможностей
становится понятной, если вспомнить о
богатых возможностях группировки объектов
по связям между ними (Links).

AllowedMovement
Id INTEGER Первичный ключ
ContainerId INTEGER REFERENCES ObjType(Id) Ссылка на тип объекта-хранилища
ContentId INTEGER REFERENCES ObjType(Id) Ссылка на тип перемещаемого объекта

Что относится к объектам базы данных

Триггер на таблицу Movement
не допускает создания записей с
недопустимыми (то есть отсутствующими в AllowedMovement)
типами объектов.

PriceType
Id INTEGER Первичный ключ
Code CHAR(10) Краткое название типа цены
ItemName CHAR(30) Полное название типа цены, используется только для интерфейса
Price
Id INTEGER Первичный ключ
TypeId INTEGER REFERENCES PriceType(Id) Ссылка на тип цены
WhereId INTEGER REFERENCES Objects(Id) Ссылка на объект, по которому установлена цена. Это может быть наша фирма,
участок обмена валюты, валютная биржа, фирма-контрагент и т.п.
ObjectId INTEGER REFERENCES Objects(Id) Ссылка на объект, цена которого устанавливается данной записью
CurrencyId INTEGER REFERENCES Objects(Id) Ссылка на объект, в единицах которого выражена цена
Value DECIMAL(20,4) Цена
PriceDate DATETIME Дата, начиная с которой действует цена

Таким образом, мы можем задать любое
количество цен по любому объекту. Например,
товар по оприходованию получает входную
цену, затем ему назначается долларовая цена,
а впоследствии, время от времени, начиная с
каких-то дат — рублевая. Каждая
из подсистем учета (бухгалтерия, торговый
зал и т.п.

Отчеты

Отчеты используются для форматирования, сведения и показа данных. Обычно отчет позволяет найти ответ на определенный вопрос, например «Какую прибыль в этом году принесли нам наши клиенты?» или «В каких городах живут наши клиенты?» Отчеты можно форматировать таким образом, чтобы информация отображалась в наиболее читабельном виде.

Запросы

https://www.youtube.com/watch?v=ytadvertiseru

Модификация и выбор данных, изменение
метаданных и некоторые другие операции
осуществляются с помощью запросов (query). Большинство
современных СУБД (и некоторые средства
разработки приложений) содержат средства для
генерации таких запросов.

Один из способов манипуляции данными
называется «queries by example» (QBE) —
запрос по образцу. QBE представляет собой средство
для визуального связывания таблиц и выбора
полей, которые следует отобразить в результате
запроса.

В большинстве СУБД (за исключением некоторых настольных) визуальное построение
запроса с помощью QBE приводит к генерации текста запроса с помощью специального
языка запросов SQL (Structured Query Language). Можно также написать запрос
непосредственно на языке SQL.

Курсоры

Нередко результатом запроса является
набор из строк и столбцов (dataset). В отличие от реляционной таблицы в таком
наборе строки упорядочены, и их порядок
определяется исходным запросом (и иногда —
наличием индексов). Поэтому мы можем определить
текущую строку в таком наборе и указатель на нее,
который называется курсором (cursor).

Большинство современных СУБД поддерживают так называемые двунаправленные курсоры
(bi-directional cursors), позволяющие перемещаться по результирующему набору
данных как вперед, так и назад. Однако некоторые СУБД поддерживают только однонаправленные
курсоры, позволяющие перемещаться по набору данных только вперед.

Язык SQL

Structured Query Language (SQL) — это
непроцедурный язык, используемый для
формулировки запросов к базам данных в
большинстве современных СУБД и в настоящий
момент являющийся индустриальным стандартом.

Непроцедурность языка означает, что на нем
можно указать, что нужно сделать с базой данных,
но нельзя описать алгоритм этого процесса. Все
алгоритмы обработки SQL-запросов генерируются
самой СУБД и не зависят от пользователя. Язык SQL
состоит из набора операторов, которые можно
разделить на несколько категорий:

  • Data Definition Language (DDL) — язык определения данных, позволяющий создавать,
    удалять и изменять объекты в базах данных
  • Data Manipulation Language (DML) — язык управления данными, позволяющий
    модифицировать, добавлять и удалять данные в имеющихся объектах базы данных
  • Data Control Languages (DCL) — язык, используемый для управления пользовательскими
    привилегиями
  • Transaction Control Language (TCL) — язык для управления изменениями, сделанными
    группами операторов
  • Cursor Control Language (CCL) — операторы для определения курсора, подготовки
    операторов SQL к выполнению и некоторых других операций.

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

Расширения SQL

Выше мы уже отмечали, что триггеры и
хранимые процедуры пишутся на процедурном языке,
характерном для данной СУБД. В большинстве СУБД
такие языки представляют собой процедурные
расширения SQL и помимо обычных операторов SQL
содержат некоторый набор алгоритмических
конструкций, например begin…end, if…then…else
и т.д.

В отличие от самого языка SQL, подчиняющегося стандарту ANSI, расширения SQL
не стандартизованы. У каждой СУБД есть свой диалект процедурных расширений SQL
(в СУБД Oracle он называется PL/SQL, в СУБД Microsoft SQL Server — Transact-SQL
и т.д.).

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

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

Построение клиентской части

В роли клиентской части для такой БД, как
правило, выступает сервер приложений,
реализующий слой бизнес-логики. Для
его создания реализуется иерархия классов

TBaseDBObject
   --TInvoice
   --TEmployee
  ...  

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

https://www.youtube.com/watch?v=https:accounts.google.comServiceLogin

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

КомпьютерПресс 8’2001

Макросы

Дополнительные сведения о макросах см. в статье Общие сведения о программировании в Access.

Модули

Подобно макросам, модули — это объекты, с помощью которых базу данных можно сделать более функциональной. Но если макросы в Access составляются путем выбора из списка макрокоманд, модули создаются на языке Visual Basic для приложений (VBA). Модули представляют собой наборы описаний, инструкций и процедур.

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

Дополнительные сведения о модулях см. в статье Общие сведения о программировании в Access.

Выноска 4https://www.youtube.com/watch?v=ytpressru

К началу страницы