\documentclass[a4paper,11pt, titlepage]{article}
\usepackage[utf-8]{inputenc}
\usepackage[russian]{babel}

\usepackage{graphicx} %вставка графики

\usepackage{indentfirst} %отступ перед первой буквой параграфа

%замена : на . в подписях к рисункам
\usepackage[centerlast,small]{caption2}
\renewcommand{\captionlabeldelim}{.} 

%макет страницы по ГОСТ7.32-2001
%\usepackage[english]{layout}
\renewcommand{\baselinestretch}{1.3}
\voffset-20mm %стандартные поля LaTeX == 1 дюйму (2.54) вычитаем лишнее =) что то не совсем так. значения подобраны
\hoffset-20mm 
\textheight250mm
\textwidth170mm
\parindent5mm


%opening
\title{Курсовая работа по дисциплине <<Технологии баз данных>> \\Вариант 1 <<Мебель>>}
\author{Выполнил студент группы 3332 Ларин Анатолий}

\begin{document}
%\layout %выводит разметку страницы
\maketitle
%\thispagestyle{empty}

\tableofcontents
\pagebreak

\section{Постановка~задачи}
База данных предназначена для информационной поддержки деятельности менеджера по продажам на мебельном производстве.
В базе данных хранятся сведения о продукции, заказах, заказчиках, а также график отгрузки заказов.

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

Сохраняемая информация о заказчиках включает наименование заказчика (Ф.И.О. физического лица или название юридического), вид заказчика (физическое лицо/юридическое лицо), адрес, телефон, факс, e-mail. Если заказчик является юридическим лицом и осуществляет оплату по безналичному расчету, то указывается: банк, счет, БИК, ИНН, ОКОНХ, ОКПО. Указывается также информация о городе и районе (только по Санкт-Петербургу).

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

В базе данных содержится и основная информация о продаваемой продукции: наименование, производственная цена, цена для продажи.

Наконец, календарь отгрузок содержит информацию об отгрузке с указанием транспортного средства, экспедитора, ответственного за отгрузку, планируемой даты отгрузки, времени, статусе результата (произведена/не произведена).

\section{Первичная~структура~базы~данных}
На рисунке \ref{stage1} показана первоначальная структура базы данных, полученная методом обратного проектирования в ERwin.

Отметим некоторые недостатки существующей базы данных:
\begin{itemize}
\item В заказе может быть не больше четырех позиций. Если позиций меньше, в клиентском приложении все равно придется проверять все четыре поля.
\item Продукт идентифицируется по названию, это не позволяет ввести в базу продукцию с одинаковыми названиями, но разными артикулами (напр. разный цвет,  партия). Так же это ведет к увеличению размеров индекса и замедлению выполнения операций с базой данных.
\item Контроль за правильностью данных (электропочта, номера телефонов, адрес, стоимость) должен осуществляться приложением.
\item Менеджер, экспедитор и транспортные средства представлены обычными строками, что не позволяет хранить дополнительные данные о них и ведет к аномалиям.
 \end{itemize}
 
 Из вышеперечисленных недостатков, можно сделать вывод, что база нуждается в перепроектировании.

\begin{figure}
	\centering
	\includegraphics[scale=0.6]{stage1/model.png}
 	\caption{ER диаграмма. Первичная структура базы данных.}
 	\label{stage1}
\end{figure}
\clearpage

\section{Проектирование~базы~данных}
В данном разделе рассматривается основная часть курсовой работы --- проектирование базы данных. 

Постепенно будут описаны все этапы проектирования, начиная с модели предметной области и заканчивая конкретной реализацией на СУДБ Firebird.
\subsection{Проектирование~модели~предметной~области~с~использованием~UML}
В рассматриваемой предметной области мы можем выделить следующие объекты:
\begin{itemize}
\item продукт;
\item заказ;
\item заказчик;
\item отгрузка.
\end{itemize}
Рассмотрим каждый объект в отдельности.

\subsubsection{Продукт}
Объект продукт обладает следующими атрибутами:
\begin{itemize}
\item название;
\item себестоимость;
\item цена для продажи.
\end{itemize}

Можно обратить внимание на два атрибута себестоимости и цены. Для них не очень подходят целочисленные типы данных (цены не могут быть отрицательными, нулевыми, для работы с копейками придется делить цены в клиентском приложении на 100), как и не подходят дробные типы (отрицательные и нулевые цены, избыточная точность, неравномерность разрядной сетки). Предполагая, что предприятие использует рублевые цены и не торгует эксклюзивной мебелью мы можем ввести дополнительный тип данных Money. Он должен иметь два дробных разряда и недопускать чисел меньших или равных нулю и больших миллиона.

Объект продукт ассоциативно связан с заказом, причем не все продукты могут состоять в заказах.
\subsubsection{Заказ}
Атрибуты заказа:
\begin{itemize}
\item менеджер;
\item стоимость;
\item стоимость со скидкой;
\item дата приема;
\item дата планируемого завершения;
\item дата фактического завершения.
\end{itemize}

Для стоимостей применим описанный нами выше тип данный Money.

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

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

\subsubsection{Заказчик}
Атрибуты заказчика:
\begin{itemize}
\item имя физического лица или ответственного сотрудника юридического лица;
\item название юридического лица;
\item вид заказчика (физическое/юридическое);
\item адрес;
\item телефон;
\item факс;
\item e-mail;
\item данные о безналичном расчете.
\end{itemize}

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

Для e-mail введем новый тип данных состоящий из имени пользователя и домена.

Для адреса также введем соответствующий тип данных.

Из объекта заказчик можно выделить два объекта юридическое и физическое лицо, потомков объекта заказчик, тогда в родительском объекте останутся следующие атрибуты:
\begin{itemize}
\item адрес;
\item телефон;
\item факс;
\item e-mail.
\end{itemize}

Заказчик ассоциативно связан с объектом заказ, причем у заказчика на данным момент может не быть заказов.
\subsubsection{Физическое~лицо}
Атрибуты:
\begin{itemize}
\item имя;
\item отчество;
\item фамилия.
\end{itemize}

\subsubsection{Юридическое~лицо}
У объекта юридическое лицо остается только один атрибут --- название.

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


\subsubsection{Отгрузка}
Атрибуты отгрузки:
\begin{itemize}
\item планируемая дата;
\item планируемое время;
\item экспедитор;
\item транспортное средство;
\item статус результата.
\end{itemize}

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

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

\subsubsection{Транспортное~средство}
Атрибуты транспортного средства:
\begin{itemize}
\item тип;
\item регистрационный номер;
\item водитель.
\end{itemize}

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

\subsubsection{Сотрудник}
Атрибуты объекта сотрудник:
\begin{itemize}
\item имя;
\item фамилия;
\item дата рождения;
\item номер пасспорта;
\item должность;
\item телефон.
\end{itemize}

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

Для атрибута должность стоило бы ввести отдельный объект, но в рамках курсовой работы мы этого делать не будем.

\subsubsection{UML~диаграмма}
\begin{figure}[hbt]
	\centering
	\includegraphics[scale=0.6]{stage2.png}
 	\caption{UML диаграмма. Модель предметной области.}
\end{figure}
\clearpage

\subsection{Проектирование~модели~базы~данных~с~использованием~ERwin}
Используя результаты предыдущего пункта смоделируем базу данных в ERwin.

\subsubsection{Домены}
Для всех введенных нами типов данных создадим домены:
\begin{description}
\item[Адрес] Определим домен как строку переменной длины и возложим выполнение проверок корректности на клиентские приложения.
\item[Стоимость] Для стомости идеально подходит тип DECIMAL с 7 целыми и двумя дробными разрядами. Ограничение для домена: \verb'VALUE BETWEEN 0 AND 1000000 OR VALUE IS NULL'.
\item[Электронная почта] Определим домен как строку переменной длины. Ограничением для домена будет сравнение с маской \verb'_%@_%._%'. 
\item[Телефон] Определим домен как строку переменной длины. Телефон может быть городским (маска \verb'_%') так и междунородным или мобильным (маска \verb'+_%(_%)_%').
\end{description}

Так как в FireBird отсутствует булевый тип данных придется определить домен BOOL типа SMALLINT с ограничением \verb'VALUE IN (0, 1)'
 

\subsubsection{Сущности}
Определим сущности, составляющие нашу диаграмму. 

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

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

Также необходимо добавить сущностью PRODUCTS\_IN\_ORDER, возникающую при разбиении отношения (ассоциативной связи) многие-ко-многим между заказом и продуктом. Эта сущность будет определять продуктовый состав заказа.

Атрибуты всех сущностей дополним суррогатными первичными ключами.

Окончательный набор сущностей:
\begin{itemize}
\item PRODUCT
\item PRODUCTS\_IN\_ORDER
\item ORDER
\item CLIENT
\item WRITTENORDER
\item SHIPMENT
\item TRANSPORT
\item EMPLOYEE
\end{itemize}

\subsubsection{Отношения}
Отношения ER-модели строятся из связей модели предметной области.
 
Обобщающие связи не переносятся, из-за объединения потомков с родителем в одну сущность.
 
Связи имеющие с обеих сторон множественную кратность разбиваются при помощи выделения новой сущности, к которой от связанных ранее сущностей строятся отношения один-ко-многим.

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

\subsubsection{ER~диаграмма}
\begin{figure}[hbt]
	\centering
	\includegraphics[scale=0.6]{stage3/phyzical.png}
 	\caption{ER диаграмма. Модель базы данных.}
\end{figure}
\clearpage

\section{Создание~базы~данных}
В этом разделе описана реализация предложенной выше модели для СУБД firebird.

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

\subsection{Тригеры}
\subsubsection{Суррогатные~ключи}
Для каждого введенного нами суррогатного первичного ключа требуется ввести тригеры и генераторы. Генерирующие новое значение ключа увеличением значения генератора на единицу. Оставлена возможность ручной установки ключа без изменения генератора, для передачи каких-либо специфичных значений, или взаимодействия с IBExpert (свойство genfield).

Тригеры добавляются по образцу:
\begin{verbatim}
CREATE GENERATOR <имя генератора>; //Создание генератора
SET GENERATOR <имя генератора> TO 1;//Инициализация генератора

/*Тригер использующий генератор, при пустом значении ID*/
CREATE TRIGGER <имя тригера> for <имя таблицы>
active before insert position 0
as
begin
  if ((new.<имя поля> is null) or (new.<имя поля> = 0)) then
  begin
    new.<имя поля> = gen_id(<имя генератора>, 1);
  end
end;
\end{verbatim}

\subsubsection{Запрет~удаления~невыполненной~отгрузки}
Этот тригер помогает поддерживать целостность базы данных, предотвращая случайное (или злоумышленное) удаление невыполненной отгрузки. Предусмотрен вариант удаления случайно созданной отгрузки, если поле транспорт пусто, тригер позволит удалить отгрузку. 

В добавление к тригеру создается исключение, вызываемое при нарушении условий.

\begin{verbatim}
CREATE EXCEPTION NO_READY_SHIPMENT_DELETE 'Ошибка удаения. Отгрузка еще не совершена';
CREATE TRIGGER tdel_Shipment FOR Shipment BEFORE DELETE AS
BEGIN
    if((OLD.completed<>1) AND (OLD.id_transport IS NOT NULL)) 
        THEN EXCEPTION NO_READY_SHIPMENT_DELETE;
END;
\end{verbatim}

\subsubsection{Подсчет~стоимости~заказа}
Приведенный ниже скрипт создает набор тригеров обеспечивающих подсчет стоимости заказа.

Предполагая, что фирма будет иметь дело с огромными заказами, стоимость не подсчитывается суммированием стоимости позиций при каждой изменении базы. Создается три тригера на добавление, изменение или удаление из таблицы PRODUCTS\_IN\_ORDER. Тригер на добавление суммирует стоимость добавленной позиции со стоимостью заказа, тригер на удаление вычитает стоимость удаленной позиции, а тригер на изменение вычитает старую стоимость и добавляет новую (срабатывая только на смену продукта или количества, но не заказа). 

\begin{verbatim}
CREATE TRIGGER tins_Products_in_Order FOR Products_in_Order
ACTIVE
AFTER INSERT AS
DECLARE VARIABLE addCost DECIMAL(2);
BEGIN
    SELECT (costPrice*NEW.pcount) FROM Product 
        WHERE Product.id_product = NEW.id_product INTO addCost;
    UPDATE Orders SET ncost = (ncost + :addCost);
END;

CREATE TRIGGER tdel_Products_in_Order  FOR Products_in_Order 
ACTIVE
AFTER DELETE AS
DECLARE VARIABLE subCost DECIMAL(2);
BEGIN
    SELECT (costPrice*OLD.pcount) FROM Product 
        WHERE Product.id_product = OLD.id_product INTO subCost;
    UPDATE Orders SET ncost = (ncost - :subCost);
END;

CREATE TRIGGER tupd_Products_in_Order FOR Products_in_Order 
ACTIVE
AFTER UPDATE AS
DECLARE VARIABLE addCost DECIMAL(2);
DECLARE VARIABLE subCost DECIMAL(2);
BEGIN
    IF((OLD.pcount<>NEW.pcount) OR (OLD.id_product<>NEW.id_product) ) THEN
    BEGIN
        SELECT (costPrice*OLD.pcount) FROM Product 
            WHERE Product.id_product = OLD.id_product INTO subCost;
        SELECT (costPrice*NEW.pcount) FROM Product 
            WHERE Product.id_product = NEW.id_product INTO addCost;
        UPDATE Orders SET ncost = (ncost - :subCost + :addCost);
    END
END;
\end{verbatim}

\subsection{Хранимые~процедуры}

\subsubsection{Увольнение~сотрудника}
Процедура \verb'TRUMP_EMPLOYEE' призвана помочь директору при увольнении сотрудника. 

Процедура принимает на входе два параметра \verb't_empl_id' --- номер увольняемого сотрудника и \verb'new_empl_id' --- номер сотрудника, которому передаются дела уволенного. Скрипт проходит по таблицам TRANSPORT, SHIPMENT, ORDERS заменяя номер увольняемого на номер нового сотрудника, а затем удаляет старого сотрудника из базы данных.

\begin{verbatim}
CREATE PROCEDURE TRUMP_EMPLOYEE(t_empl_id INTEGER, new_empl_id INTEGER) AS
BEGIN
 UPDATE TRANSPORT SET id_employee = :new_empl_id WHERE id_employee = :t_empl_id;
 UPDATE SHIPMENT SET id_employee = :new_empl_id WHERE id_employee = :t_empl_id;
 UPDATE ORDERS SET id_employee = :new_empl_id WHERE id_employee = :t_empl_id;

 DELETE FROM ORDERS WHERE id_employee = :t_empl_id;
END;
\end{verbatim}

\subsubsection{Архивация~выполненных~заказов}
Выполненные заказы продолжают хранится в нашей базе (для разрешения претензий, составления статистики), увеличивая время поиска, вставки и обновления. Поэтому было бы разумным хранить важные данные о выполненных заказах в другой таблице.

Нижеследующих код создает архивную таблицу и процедуру \verb'ARCHIVE_ORDERS' архивирующую заказы.

Процедура принимает на входе параметр \verb'before_date' определяющий дату, до которой следует архивировать выполненные заказы. Дальнейший процесс состоит в выборке нужных заказов, посчете требуемых данных, записи в архивную таблицу и наконец удаления из старой.


\begin{verbatim}
/*Архивная таблица*/
CREATE TABLE ORDERS_ARCHIVE (
       id_order             INTEGER NOT NULL,
       endDate              DATE,
       ncost                MONEY DEFAULT 0,
       id_employee          INTEGER NOT NULL,
       id_client            INTEGER NOT NULL,
       pcount               INTEGER NOT NULL
);


CREATE PROCEDURE ARCHIVE_ORDERS(before_date DATE) AS
DECLARE VARIABLE id_order INTEGER;
DECLARE VARIABLE endDate DATE;
DECLARE VARIABLE ncost DECIMAL(2);
DECLARE VARIABLE managerName VARCHAR(50);
DECLARE VARIABLE employeeName VARCHAR(50);
DECLARE VARIABLE pcount INTEGER;
BEGIN
    FOR
    SELECT ord.id_order, endDate, ncost, 
        emp.firstName||emp.lastName, cl.firstName||cl.lastName
    FROM ORDERS ord LEFT JOIN EMPLOYEE emp ON emp.id_employee = ord.id_employee
    LEFT JOIN CLIENT cl ON cl.id_client = ord.id_client
    WHERE endDate > :before_date
    INTO :id_order, :endDate, :ncost, :managerName, :employeeName
    DO
    BEGIN
        SELECT SUM(pcount) FROM PRODUCTS_IN_ORDER WHERE id_order = :id_order INTO :pcount;
        INSERT INTO ORDERS_ARCHIVE VALUES
            (:id_order, :endDate, :ncost, :managerName, :employeeName, :pcount);

        DELETE FROM PRODUCTS_IN_ORDER WHERE id_order = :id_order;
        DELETE FROM SHIPMENT WHERE id_order = :id_order;
    END
    DELETE FROM ORDERS WHERE endDate>:before_date;
END;
\end{verbatim}


\subsubsection{Популярность~продуктов}
Процедура вывода, позволяющая оценить популярность продукции (по заказам) в процентном соотношении. Получение этих данных с помощью View невозможно по причине необходимости подсчета процентов.

\begin{verbatim}
CREATE PROCEDURE PRODUCTS_POPULARITY 
    RETURNS (name VARCHAR(50), popularity DECIMAL(2)) AS
DECLARE VARIABLE allcount INTEGER;
BEGIN
    SELECT SUM(pcount) FROM PRODUCTS_IN_ORDER into allcount;
    FOR
        SELECT name, SUM(pcount) FROM PRODUCTS_IN_ORDER
        LEFT JOIN PRODUCT ON 
            PRODUCT.id_product = PRODUCTS_IN_ORDER.id_product
        GROUP BY name INTO :name, :popularity
    DO BEGIN
        popularity = popularity / allcount;
        SUSPEND;
    END
END;
\end{verbatim}

\subsection{<<Представления>>}
\subsubsection{Активность~менеджеров}
Данное представление помогает получить поименный список менеджеров и количества заказов, обслуживаемых каждым из них. Это позволяет директору выявлять загруженность и активность своих сотрудников.

\begin{verbatim}
CREATE VIEW MANAGERS_ORDERS (name , ordersCount) AS
    SELECT firstName ||' '|| lastName, COUNT(id_order)
        FROM ORDERS LEFT JOIN EMPLOYEE 
            ON ORDERS.id_employee = EMPLOYEE.id_employee
        GROUP BY firstName, lastName;
;
\end{verbatim}


\subsection{Тестовые~данные}
Для разработки демонстрационного приложения нам потребуются тестовые данные. Данный скрипт производит начальное заполнение базы данных.
\begin{verbatim}
/* Продукция */
INSERT INTO PRODUCT VALUES (0, 'Стул',10,100);
INSERT INTO PRODUCT VALUES (0, 'Кресло',20,200);
INSERT INTO PRODUCT VALUES (0, 'Мягкое кресло',30,300);
INSERT INTO PRODUCT VALUES (0, 'Табурет',5,50);
INSERT INTO PRODUCT VALUES (0, 'Раскладушка',25, 250);
INSERT INTO PRODUCT VALUES (0, 'Кровать',35,350);
INSERT INTO PRODUCT VALUES (0, 'Кресло-кровать',56,560);
INSERT INTO PRODUCT VALUES (0, 'Диван',89,890);
INSERT INTO PRODUCT VALUES (0, 'Кожаный диван',167,2000);
INSERT INTO PRODUCT VALUES (0, 'Водяная кровать', 60, 1500);

/*Сотрудники*/
INSERT INTO EMPLOYEE VALUES(0, 'Николай', 'Требушев', 
    '+7(904)4444444', '234567', 'Генеральный директор', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Петр', 'Власов', 
    '+7(904)4444444', '234568', 'Старший менеджер', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Станислав', 'Броцкий', 
    '+7(904)4444444', '234569', 'Менеджер', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Иван', 'Куров', 
    '+7(904)4444444', '2345611', 'Менеджер', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Виктор', 'Малышев', 
    '+7(904)4444444', '2345612', 'Старший техник', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Вера', 'Горкова', 
    '+7(904)4444444', '2345613', 'Водитель', '23.02.1967');
INSERT INTO EMPLOYEE VALUES(0, 'Слава', 'Роботам', 
    '+7(904)4444444', '2345614', 'Водитель', '23.02.1967');

/*Транспорт*/
INSERT INTO TRANSPORT VALUES(0, 0, 'а666дд', 6);
INSERT INTO TRANSPORT VALUES(0, 1, 'м777яс', 7);

/*Клиенты*/
INSERT INTO CLIENT VALUES(0,'Профессора Попова 5', 0, 
    '+7(821)4444444', '5555555', 'yuriy@pupkin.info', 'Юрий', 'Киров', NULL);
INSERT INTO CLIENT VALUES(0,'наб. реки Мойки 20', 0, 
    '+7(821)4444444', '5555555', 'marya@pupkin.info', 'Марианна', 'Белоусова', NULL);
INSERT INTO CLIENT VALUES(0,'Советовская 34', 0, 
    '+7(821)4444444', '5555555', 'kostya@pupkin.info', 'Константин', 'Першин', NULL);

INSERT INTO CLIENT VALUES(0,'Проспект пионеров 122а', 1, '+7(821)4444444', 
    '5555555', 'kolebas@rogaikopita.info', 'Григорий', 'Калебас', 'Рога и Копыта');
INSERT INTO CLIENT VALUES(0,'Невский 56', 1, '+7(821)4444444', 
    '5555555', 'orders@zlatovlaska.ru', 'Татьяна', 'Крашенникова', 'Златовласка');
INSERT INTO CLIENT VALUES(0,'Проспект просвещения 6', 1, '+7(821)4444444', 
    '5555555', NULL, 'Ашот', 'Гигашвили', 'Шаурма сервис');
\end{verbatim}

\section{Демонстрационное~приложение}
\subsection{Назначение}
Реализуемая программа предназначена для управления заказами. Она позволяет добавлять, удалять и модифицировать заказы и их состав.

\subsection{Структура~программы}
Для доступа к базе данных были выбраны компоненты IBExpert, так как в отличие от BDE не нужно устанавливать на компьютер клиента дополнительные библиотеки; компоненты разработаны специально для Inter Base, что гарантирует скорость, стабильность и реализацию большинства возможностей этой СУБД. dbExpress был отброшен сразу, по причине того, что не работает.

Основным компонентом доступа к базе данных является TIBDatabase, настроенный на подключение к СУБД. 

Для управления транзакциями (выбрана автоматическая модель управления) используется TIBTransaction.

Для работы пользователя с данными используются компоненты TDBGrid, связанные через TDatasource с компонентами TIBDataset, которые реализуют доступ к базе данных использую заданные пользователем запросы.

Запросы для управления заказами:
\begin{description}
\item{Выборка:}
\begin{verbatim}
SELECT id_order AS oid_order, regDate, planDate, 
    endDate, ncost, id_employee, id_client
FROM ORDERS
\end{verbatim}
\item{Обновление строки:} 
\begin{verbatim}
SELECT id_order AS oid_order, regDate, planDate, 
    endDate, ncost, id_employee, id_client
FROM ORDERS WHERE id_order = :oid_order
\end{verbatim}
\item{Вставка:} 
\begin{verbatim}
INSERT INTO 
ORDERS (id_order, ncost, regDate, endDate, planDate, id_employee, id_client) 
VALUES (:oid_order,0, CURRENT_DATE, :endDate, :planDate, :id_employee, :id_client)
\end{verbatim}
\item{Удаление:} 
\begin{verbatim}
DELETE FROM ORDERS WHERE id_order = :oid_order
\end{verbatim}
\item{Модификация:} 
\begin{verbatim}
UPDATE ORDERS SET planDate = :planDate, endDate = :endDate, 
    id_employee = :id_employee, id_client = :id_client
WHERE id_order = :oid_order
\end{verbatim}
\end{description}

Запросы для управления составом заказа:
\begin{description}

\item{Выборка:} 
\begin{verbatim}
SELECT id_order, id_product, pcount FROM PRODUCTS_IN_ORDER 
WHERE id_order = :oid_order
\end{verbatim}

\item{Обновление строки:} 
\begin{verbatim}
SELECT id_order, id_product, pcount FROM PRODUCTS_IN_ORDER 
WHERE id_order = :id_order AND id_product = :id_product
\end{verbatim}
\item{Вставка:} 

\begin{verbatim}
INSERT INTO PRODUCTS_IN_ORDER(id_order, id_product,pcount)
VALUES (:id_order, :id_product, :pcount)
\end{verbatim}

\item{Удаление:}
\begin{verbatim}
DELETE FROM PRODUCTS_IN_ORDER 
WHERE id_product = :id_product AND id_order=:id_order
\end{verbatim}

\item{Модификация:} 
\begin{verbatim}
UPDATE PRODUCTS_IN_ORDER 
SET id_product = :new_id_product, pcount = :new_pcount
WHERE id_product = :old_id_product AND id_order = :old_id_order
\end{verbatim}

\end{description}

Для связи между заказами и их составом использовалась связь master/detail (свойство DataSource) по полю id\_order.

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

\subsection{Изображение~главного~окна}
\begin{figure}[hbt]
	\centering
	\includegraphics[scale=0.6]{program/screenshot.png}
 	\caption{Изображение главного окна программы.}
\end{figure}

\end{document}

