2.4 Построение даталогической модели
Предметная область, выбранная мною для данной курсовой работы – информация о клиентах, дисках и выдаче дисков небольшого видеопроката.
Целью данной работы является автоматизация обработки данных по клиентам с целью упрощения работы персонала с клиентами. При покупке или выдаче на прокат товара клиенту выдаётся чек. Количество товара на складе соответственно уменьшается. Также в видеопрокате существуют скидки постоянным клиентам в зависимости от количества покупок (сделок).
В процессе реализации задачи при разработке структуры для хранения данных, первым объектом выступают информация о товаре (дисках или кассетах) и клиентах. В нашем случае БД будет состоять из 3 таблиц. В таблице MOVIE будут содержаться сведения о фильмах (штрих-код, количество дисков, название, режиссер и жанр). В таблице CLIENT будут храниться все нужные сведения о клиентах – с указанием полных паспортных данных. Третья таблица DEAL будет содержать сведения о сделках (дата сделки, сумма с учетом скидки (если она есть) и т.д.) Таким образом, таблица DEAL будет центральной. Она должна будет иметь уникальной поле, которое будет однозначно определять каждую сделка. В дальнейшем по этому полю мы создадим первичный ключ, чтобы СУБД могла быстро найти нужную запись. Каждой записи в таблице MOVIE будет соответствовать произвольное количество записей в таблице DEAL (такая связь в терминологии БД называется связью один ко многим), т. е. одно из её полей будет содержать уникальный идентификатор фильма. В таблице DEAL будет также ссылка на уникальный идентификатор клиента из таблицы CLIENT. При появлении очередной записи в таблице DEAL должно меняться значение поля KOL (количество) в таблице MOVIE.
Таблица Фильмы (MOVIE):
ID | Целый | INTEGER | Уникальный идентификатор фильма. По этому полю создается первичный ключ. (штрих код диска) |
NAME_FILM | Строковый | VARCHAR 50 | Название фильма (индексное поле) |
DIRECTOR | Строковый | VARCHAR 50 | Режиссер |
GANR | Строковый | VARCHAR 10 | Жанр (набор фиксированных значений: комедия, триллер, боевик и т. д.) Индексное поле |
KOL | Целый | INTEGER | Количество на складе |
MONEY | Целый | INTEGER | Цена |
DESCRIPTION | Строковый | VARCHAR 250 | Краткое описание фильма |
Таблица Клиенты(CLIENT):
ID_C | Целый | INTEGER | Уникальный идентификатор клиента (первичный ключ) |
FIO | Строковый | VARCHAR 50 | ФИО (индексное поле) |
PASPORT | Строковый | VARCHAR 150 | Паспортные данные |
Таблица Заказы(DEAL):
ID_D | Целый | INTEGER | Уникальный идентификатор (первичный ключ) |
ID_M | Целый | INTEGER | Код фильма из поля ID таблицы MOVIE |
CL_ID | Целый | INTEGER | Код клиента из поля ID_C таблицы CLIENT |
DEN | Вещественный | NUMERIC | Цена с учетом скидки |
D_D | Дата | DATE | Дата составления. По этому полю нужно создать индекс для сортировки. |
VZVR | Символьный | CHAR 1 | Код возврата. По умолчанию ‘N’ |
Таблица Log
WHEN | Дата | TIMESTAMP | Дата редактирования(текущая дата) |
USER | Строковый | VARCHAR(20) | Пользователь |
ACTION | Строковый | CHAR(3) | Действие, выполняемое пользователем |
Приложение-клиент разрабатывается при помощи программных средств Borland Delphi, используя набор компонентов Interbase Express (IBX). Эти компоненты используют функции Intebase API, т.е. обращаются к серверу непосредственно. VCL-библиотека классов среды проектирования Delphi предоставляет ряд классов, позволяющих быстро и эффективно разрабатывать различные приложения баз данных.
Эти классы представлены следующими группами:
· компоненты для доступа к данным, реализующие:
o доступ через машину баз данных BDE (Borland Database Engine), предоставляющую доступ через ODBC-драйверы или через внутренние драйверы машины баз данных BDE (компоненты страницы BDE-палитры инструментов);
o доступ через ADO-объекты (ActiveX Data Objects), в основе которого лежит применение технологии OLE DB (компоненты страницы ADO);
o доступ к локальному или удаленному SQL-серверу InterBase (компоненты страницы InterBase);
o доступ посредством легковесных драйверов dbExpress;
o доступ к БД при многозвенной архитектуре (компоненты страницы DataSnap);
· визуальные компоненты, реализующие интерфейс пользователя;
· компоненты для связи источников данных с визуальными компонентами, предоставляющими интерфейс пользователя;
· компоненты для визуального проектирования отчетов.
Компоненты для доступа к серверу InterBase:
· TIBDatabase — предназначен для подключения к базе данных. Основные методы: Open, Close.
· TIBTransaction — предназначен для явного управления транзакцией. Основные методы: StartTransaction, Commit, Rollback, CommitRetaining, RollbackRetaining.
· TIBTable — аналог стандартного TTable. Компонент предназначен для получения данных из одной таблицы или представления базы данных. Основное свойство — TableName. Основные методы: Open, Close. Набор данных, полученных при помощи TIBTable, является редактируемым, если речь идет о таблице базы данных или обновляемом представлении. Компонент совместим с визуальными компонентами.
· TIBQuery — аналог стандартного TQuery. Компонент предназначен для получения данных на основе SQL-запроса. Этот набор данных не всегда будет редактируемым, зачастую необходимо использовать дополнительный компонент TIBUpdateSQL, чтобы иметь возможность редактировать полученные сведения. Основное свойство — SQL. Основные методы: Open, Close, ExecSQL. Компонент совместим с визуальными компонентами.
· TIBDataSet — предназначен для получения и редактирования данных, является потомком стандартного класса TDataSet и полностью совместим со всеми визуальными компонентами. Основные методы: Prepare, Open, Close, Insert, Append, Edit, Delete, Refresh.
· TIBStoredProc — предназначен для выполнения хранимых процедур и получения набора данных на основе результатов выполнения процедуры. Получаемый набор данных является нередактируемым. Компонент совместим с визуальными компонентами. Основное свойство — StoredProcName. Основной метод — ЕхесРгос.
· TIBUpdateSQL — аналог TUpdateSQL. Используется в паре с TIBQuery и предназначен для создания модифицируемых наборов данных. Основные свойства: DeleteSQL, InsertSQL, ModifySQL и RefreshSQL.
· TIBSQL — предназначен для выполнения SQL-запросов. В отличие от TIBQuery или TIBDataSet, TIBSQL не имеет локального буфера для набора данных и несовместим с визуальными компонентами.
· TIBDatabaseInfo — позволяет получить системную информацию о некоторых свойствах базы данных, соединения и сервера. Например, UserNames — список пользователей, подключенных к базе данных, PageSize — размер страницы базы данных.
· TIBSQLMonitor — предназначен для перехвата и отслеживания всех запросов, которые выполняют приложения, использующие IBX.
TIBEvents — предназначен для получения пользовательских событий InterBase. Основное свойство — Events. Основные методы: RegisterEvents, UnregisterEvents.
3.2Особенности разработки приложения
С учетом назначения функциональной спецификации, а также с учетом возможности тяжелых ошибок в этом документе, функциональная спецификация должна быть очень точной и не противоречивой и по возможности приближаться к математическим формулировкам, однако это не означает что она должна быть формализована настолько, что по ней можно было бы автоматически генерировать код программы. Это означает лишь то, что она должна базироваться на понятиях, построенных как математические объекты, и утверждениях, однозначно понимаемых и заказчиком и разработчиками.
Достаточно часто функциональная спецификация формализуется на естественном языке, тем не менее использование математических и других формализованных методов при разработке функциональной спецификации весьма приветствуется.
В целом функциональная спецификация состоит из трех основных частей:
1. Описание внешней информационной среды по отношению к программному средству;
2. Определение функций ПС. Чаще всего такие функции рассматриваются на множестве состояний внешней информационной среды;
3. Описание нежелательных ситуаций, которые могут возникнуть при работе ПС и описание реакции ПС на эти ситуации.
Основной функцией ПС можно считать автоматизацию процесса управления процессом принятия заказов, поиска заказов, ведение статистики и пр.
Как сказано выше, основными функциями разрабатываемого ПС являются:
- Добавление нового поступления видео-продукции с проведением маркировки. Каждое новое поступление должно быть введено в базу фильмов с заполнением всех необходимых полей. Результатом выполнения данной функции является запись в таблице базы данных и присвоение каждому видео-фильму своего индивидуального номера, с его последующим нанесением на физический носитель. Повторение индивидуального номера не допускается, поэтому необходимо либо генерировать его внутри системы. Название видео-фильма должно быть символьным и не более 50 символов. Число копий должно быть целым числом. Поля «Носитель», «Категория», «Производство фильма (Страна)», заполняются из выпадающих списков.
- Регистрация новых клиентов пункта проката. Регистрация клиентов производится только при наличии паспорта. При регистрации необходимо обязательно заполнить поля «№ паспорта», «Фамилия», «Имя», «Отчество», остальные поля не обязательными для заполнения. Также необходимо проводить проверку на совпадение вводимой информации при регистрации нового клиента по всем обязательным параметрам в совокупности и при совпадении необходимо выводить соответствующее сообщение. Поля «Фамилия», «Имя», «Отчество», «Адрес» являются символьными и ограничены 50 символами.
- Быстрый поиск видео-продукции по индивидуальному номеру, категории, типу носителя, названию. Результатом работы функции является список видео-продукции, отобранный по определенному критерию, или группе критериев. Поле «Название» является символьным и должно содержать название искомой продукции, поле «Индивидуальный номер» является целым числовым, другие поля заполняются из выпадающего списка. Если не будет обнаружено ни одной записи, отвечающей критериям поиска, то должно быть выведено соответствующее сообщение.
- Возможность показа статистики заказов отдельным клиентом. Результатом работы данной функции является вывод списка с информацией о клиенте и видео-продукцией, которую он заказывал ранее. В этом списке указывается количество заказов, сделанных клиентом, размер штрафа, который он уплатил, количество дней, прошедших с момента регистрации. Также указывается количество заказов, которые клиент сделал, выбирая видео-продукцию на различных видов носителей (VHS, CD, DVD). Входной информацией является ввод в поле «Номер паспорта», который является целым числом. Также имеется возможность показа статистики заказов отдельного фильма. Результатом работы является вывод списка с информацией о количестве заказов фильма, название которого введено в поле «Название фильма», а поле «Номер паспорта» остается пустым.
- Возможность показа общей статистики. Результатом работы данной функции является вывод списка всех заказов, осуществленных предприятием. Период, за который статистика будет выведена определяется пользователем, который может в поле «Год» указать год, в поле «Месяц» указать месяц и в поле «День» указать день. В результате выведется статистка заказов на то число, которое было введено пользователем. Все перечисленные выше поля являются символьными и ограничены 8 символами и заполняются из выпадающего списка, в котором присутствует строка «все», при выборе которой должна учитываться статистика за все дни, месяцы, годы в зависимости от того в каком поле эта строка выбрана.
Исключительные ситуации должны быть обрабатываться отдельным обработчиком и перекрывать системный обработчик. Должен выполняться принцип прозрачности и пользователю помимо ошибки должны сообщаться ее причины и при его желании соответствующие справки. Локальные ошибки должны устраняться без прерывания основного процесса не подверженного ошибочным действиям. Фатальные ошибки должны отрабатываться особо и не нарушать целостности системы. В случае краха системы, должно быть обязательно предусмотрено ее восстановление предыдущей рабочей версией, с целью чего необходимо создавать архивы системы при каждом ее отключении. Создание архива системы должно быть автоматическим и не сказываться на скорость основных вычислений.
Опытным путем нетрудно выяснить, что Delphi при работе с InterBase интерпретирует столбцы типа CHAR и VARCHAR как T S t r i n g F i e l d. При этом, во-первых, столбцы типа CHAR всегда читаются без завершающих пробелов, во-вторых, при занесении завершающих пробелов в столбец (а часто это бывает необходимо) типа CHAR они всегда удаляются, в то время как в столбце типа VARCHAR, наоборот, они всегда хранятся. Столбцы типа DATE позволяют хранить значения даты в пределах от 01.01.0100 до 11.12.5941, а также значения времени (тип DATE InterBase полностью совместим с типом TDateTime Delphi). Если ввод данных в столбец типа DATE производится из утилиты IBConsole, значения даты должны указываться в формате InterBase. Согласно этому формату, значения даты состоят из номера дня (01-31), месяца (JAN-DEC) и года. Эти значения отделяются друг от друга разделителями. Стандартным разделителем является символ дефиса (-), но принимаются и пробел, правый слеш (/) и точка (.). Значения дат в InterBase должны лежать в диапазоне от 1-JAN-100 до 11-DEC-5941. Интерпретация формата представления значений типа DATE зависит от настройки — программы или операционной системы компьютера. Полезно всякий раз при старте приложения программно переустанавливать формат даты и времени к привычному нам российскому формату:
procedure TForml.FormCreate(Sender: TObject);
begin
DateSeparator:= '. ';
ShortDateFormat:= 'dd.mm.yyyy';
ShortTimeFormat:= 'hh:mm:ss';
end;
Таким образом можно игнорировать неопределенность текущей настройки операционной системы на конкретном компьютере.
В InterBase значения типа DATE совместимы со строковыми типами. Поэтому, если в SQL-операторах InterBase требуется интерпретировать значения типа DATE как строку, нет необходимости в приведении типов. Например, можно так записать в символьный столбец S значение типа DATE (символы I I означают операцию конкатенации, или сцепления, строк, функция NOW возвращает текущие дату и время):
UPDATE DEAL
SET S = "Дата отгрузки " I I NOW;
Как уже говорилось, в InterBase нет автоинкрементного типа. Поля автоинкрементного типа автоматически заполняются уникальными числовыми значениями при вводе очередной записи. Такие поля обычно используются для создания первичных ключей. Вместо автоинкрементных полей InterBase предоставляет механизм генераторов — особых программ, которые хранят некоторое значение вплоть до момента, когда оно будет использовано, после чего изменяют хранимое значение на заданную величину.
Генератор создается следующим оператором:
CREATE GENERATOR Имя_генератора
После создания генератора ему необходимо присвоить начальное значение таким оператором:
SET GENERATOR Имя_генератора ТО Начальное_значение
Для получения очередного значения генератора используется такая функция:
GEN_ID(Имя_генератора, Шаг)
Здесь Шаг — целое число, на которое изменяется текущее значение генератора. Проиллюстрируем использование генератора на примере поля ID_C таблицы CLIENT.
Создаем генератор:
CREATE GENERATOR GEN_CLIENT_ID_C;
SET GENERATOR GEN_CLIENT_ID_C TO 1;
Однажды созданный генератор хранится в БД наряду с другими ее сущностями — таблицами, индексами, хранимыми процедурами и т. п. Используем генератор при вводе очередной записи:
CREATE TRIGGER TRIG_CLIENT FOR CLIENT
ACTIVE BEFORE INSERT POSITION 0
AS BEGIN
IF (NEW.id_c IS NULL) THEN NEW.id_c = GEN_ID(gen_client_id_c,1);
END
Доменами называются заранее созданные описания столбцов. Наряду с другими сущностями БД, домены должны иметь уникальные имена. Однажды созданный домен хранится в БД и может использоваться вместо типа столбца. С помощью доменов достигается унификация типов данных, хранящихся в различных столбцах, возможно, разных таблиц.
CREATE DOMAIN D_GANR AS
VARCHAR(10) CHARACTER SET NONE
NOT NULL
CHECK (VALUE IN ('comedy', 'action', 'melodrama', 'fantasy', 'horror'))
COLLATE NONE
В InterBase нет столбцов денежного типа (Currency). Вместо них обычно используются столбцы FLOAT или DOUBLE PRECISION. При выводе их значений в визуализирующих компонентах они представляют денежные суммы как значения с плавающей запятой, что в большинстве случаев мешает их восприятию. Вернуть этим столбцам нормальный денежный вид можно либо в обработчике события OnGetText объекта-поля, либо с помощью его (объекта-поля) свойства DisplayEdit. В обработчике можно использовать оператор такого вида:
procedure TForml.QUSUMMAGetText(Sender: TField;
var Text: String;
DisplayText: Boolean);
begin
Text:= FloatToStrFfquSumma.AsFloat,
ffCurrency, 10, 2)
end;
В свойстве DisplayEdit можно указать следующую маску:
# # #, # # #. 0 0 ' р. '
Конечный результат будет одинаков, но указать маску, как мне кажется, проще.
Визуальные средства разработки запросов обеспечивают реально удобное представление решаемой задачи, помогают определить связи и условия запроса. Но в Interbase нет как таковых визуальных средств разработки запросов. Однако можно обращаться с Interbase при помощи ibExpert. Это гибкий и мощный инструмент. В нем присутствует возможность разрабатывать структуру самой БД, сохранять и выполнять скрипты на SQL, использовать множество встоенных утилит, облегчающих работу, как разработчика, так и администратора.
Загрузив ibExpert в меню Tools->Query Builder, нужно перетащить требуемые таблицы. Определить связи между ними и отметить поля, необходимые для вывода. Они появятся внизу на вкладке Selection. А на закладке Edit можно будет просмотреть текст запроса. На закладке Perfomance Analisys есть очень полезная информация о быстродействии и количестве чтений с каждой таблицы.
3.3 Разработка пользовательского интерфейсаЕсть два способа добиться хорошего оформления таблиц. Попробовать самостоятельно улучшать стандартный DBGrid или использовать компоненты сторонних производителей, предоставляющих альтернативу стандартному компоненту. При выполнении работы надо учитывать современные тенденции и стандарты, то есть делать так, чтобы программа выглядела современной, похожей на офисные приложения. Используя компоненты от EhLib можно улучшить стандартный DBGrid, добавив новые возможности: автоматический расчет итоговых значений (сумма, среднее значение, количество записей), экспорт данных и т.д.
Устаревший дизайн стандартной таблицы теперь можно легко заменить стильной конструкцией DBGridEh, изменив свойство Flat. Также есть богатый выбор различных цветовых схем выделения данных.
Практически всегда, разрабатывая приложения для работы с базами данных, приходится выделять каким-нибудь образом данные, подпадающие под некоторое условие. Это может быть и уровень продаж определенной менеджера, достигший критически низкого уровня, и «минусовые» остатки на складе. Чтобы не пропустить такие происшествия, программа должна правильно выделять это в таблице. Для этого достаточно прописать в событии OnGetCellParams нужное условие и параметры выделения (размеры, цвет шрифта, цвет фона).
Важнейшим элементом работы с прикладными программами является возможность переноса данных в офисные приложения, например, в Microsoft Office. То есть часто бывает недостаточно просто создать отчет и вывести его в таблицу. Как правило, потом требуется, чтобы он был предоставлен в виде документа Excel для последующих манипуляций. Можно создавать различные OLE – объекты и, перебирая нужные записи в DataSet, копировать их в ячейки Excel. Этот способ довольно гибкий, так как позволяет формулировать качественные отчеты, предварительно оформив их. То есть добавлять заголовки, формулы, делать выделение критических данных и т.д. Но вот копирование по строкам сильно замедляет создание отчета, особенно если данных много. К тому же уйдет много времени на программирование переноса данных. Поэтому когда речь идет не о создании красивого оформления, а о скорости и простоте экспорта данных лучше использовать средства EhLib. Эта библиотека позволяет одним вызовом функции записывать содержимое таблицы в форматы.xls,.rtf,.html,.txt,.csv.
Также полезна функция копирования в буфер выделенных данных. Например, при наличии нескольких офисов, которые в течении дня обмениваются данными о наличии у них количества товара. Менеджерам достаточно скопировать нужные данные и вставить их в любое приложение: почтовый клиент, ICQ.
При работе с большими объемами данных бывает очень удобно не только отсортировывать данные по какому-либо полю, но и группировать («свернуть») по значениям одного из полей, чтобы потом можно было развернуть любую из подгрупп щелчком и просмотреть её содержимое. К примеру, организуя рассылку товаров по множеству городов по неким направлениям, не всегда удобно листать отсортированный по городам массив данных. Удобнее сгруппировать данные по городу и разворачивать города только нужного направления. Используя DropDownBox в DBGridEh, можно легко решать подобные задачи.
Менеджеру будет удобнее просматривать отчёты о продажах используя привычный Excel.(Рис.1) Для начала нужно установить драйвер ODBC Firebird. Запустить Excel. Выбрать меню Данные, Импорт внешних данных, Создать запрос. После проверки запроса необходимо обязательно сохранить запрос (кнопка с изображением дискеты). Запрос будет сохранен вместе со всеми параметрами алиаса, поэтому для "распространения" запроса на несколько компьютеров вовсе необязательно создавать алиас ODBC на каждом (конечно, ODBC-драйвер и клиентскую часть IB/FB все равно придется устанавливать на этих компьютерах).
CREATE PROCEDURE NEW_PROCEDURE
returns (
kld numeric(15,0),
movie varchar(50),
famio varchar(50))
as
declare variable idm integer;
declare variable cl integer;
declare variable dt date;
begin
for select deal.cl_id, deal.d_d, deal.id_m
from deal
into:cl,:dt,:idm
do
begin
kld = current_date - dt;
if (:kld > 12) then
begin
select client.fio from client where client.id_c =:cl
into:famio;
select movie.name_film from movie where movie.id =:idm
into:movie;
suspend;
end
end
end^
Инструкция пользователя
Пользовательский интерфейс построен в соответствии с классическими требованиями и правилами системы Windows, правилами системы Delphi. Основными задачами при построении интерфейса были: простота, удобство.
Программный проект включает в себя 7 оконных форм (одна из них форма главного меню), 4 из них являются непосредственно рабочими (т.е. здесь происходит ввод, обработка и корректирование данных), 3 – формы отображения обработанных данных.
При открытие программы появляется главная форма (fmMain) (Рис. 1), на которой расположены таблицы и соответствующие им элементы управления. Если есть задолжники, у которых на руках находятся диски, то вместе с главной формой появляется дочерняя форма «Задолжники»где можно увидеть наименование диска и данные задолжника и количество дней. Для удобства пользователя главная форма содержит несколько вкладок, где и находятся таблицы. Работать с базой можно как непосредственно из главной формы, так и вызвав отдельное окно из главного меню формы. Так пункт меню «Файл» содержит такие подпункты как «Новое» и «Выход». Сделать новую запись в таблице Клиенты(CLIENT) можно выбрав «Файл» -> «Новое..» -> «Клиент». После чего появится окно «Клиент» (Рис. 2), где пользователю представляется возможность заполнения каждого из предложенного полей. Кнопки «Удалить» и «Исправить» в режиме вставки не активны.
Процесс редактирования данных происходит в том же самом окне, при выборе меню «Правка» -> «Изменить..» -> «Клиент». В этом же окне появляются уведомления пользователя о недопустимых ошибках. В таблице Клиенты(CLIENT) обязательно для заполнения поле ID_C, если пользователь забывает заполнить это поле, программа уведомит его об этом.
Кнопка «Удалить» позволяет удалить запись из базы. Нельзя удалить данные о клиенте, если в таблице «Счета» есть связанные с ним записи, программа предупреждает об этом пользователя, показывая соответствующее сообщение (Рис. 4). В режиме изменение неактивна кнопка «Запись» и появляется дополнительная панель с кнопками навигации по таблице. И, наконец, для завершения работы с формой «Клиент» нужно нажать кнопку закрытия окна, и пользователь попадает на форму главного меню.
При редактировании таблицы Фильмы пользователю нужно учитывать, что невозможно удалить данные о фильме, если его количество на складе больше 0.
При выборе пункта меню «Счёт» или соответствующей вкладки главной формы пользователь может работать со счетами клиентов. При появлении окна «Новое..» -> «Счёт» пользователь должен ввести штрих код фильма и выбрать фамилию клиента, остальные поля заполняются автоматически (поля - стоимость и дата и возврат). Дата выставляется текущая, а поле стоимость изначально берется из таблицы MOVIE а потом высчитывается с учетом скидок клиенту, возврату автоматически присваивается “N”.
Когда клиент возвращает фильм, то следует поставить в этом поле “Y” в ручную или через сканер. При этом количество фильмов в базе увеличивается на 1.
На вкладке Счета также есть кнопки «Режим master detail» и «Cведенная таблица». При нажатии на кнопку «Сведенная таблица». Появляется окно с этой таблицей, которая является аналогом таблицы «Счета». Такая таблица может только отображать данные, редактировать их невозможно. Удобство её заключено в том, что листаться она будет заметно быстрее. Листание полного экрана таблицы состоящей из тысячи записей происходит в доли секунды, в то время как таблица «Счета» листается с заметными задержками.
Кнопкой «Режим master detail» можно вызвать окно, где пользователь может одновременно просматривать и редактировать данные о клиенте и его счетах.
Выбрав меню «Поиск» можно задействовать поиск по таблицам. Поиск по строковому полю позволяет искать по части слова и показывает все формы этого слова.
Последняя вкладка «SQL» (Рис. 5) позволяет продвинутым пользователям выполнять различные действия с базой данных, такие как поиск, выборка данный и т.д. Менеджеру будет удобнее просматривать отчёты используя привычный Excel. Для удобства менеджера в Excel есть отчёты по заказам за период, отчёт по персоналу, поиск лучшего клиента месяца и т.д. При этом не требуется устанавливать на машину клиентское приложение.
Список литературы
1. Фаронов В.В. Delphi 5. Руководство программиста. Нолидж. 2001.
2. Фаронов ВВ. Delphi 2005 Разработка приложений для баз данных и интернета. — СПб: Питер, 2006.
3. Хансен Г., Хансен Д. Базы данных. Разработка и управление. — М., Бином. 2000.
Приложение Листинг программы
Unit2:
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, IBCustomDataSet, Grids, DBGrids, StdCtrls, ExtCtrls, DBCtrls,
ComCtrls, IBTable, XPMan, Menus, IBQuery;
type
TForm2 = class(TForm)
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Button1: TButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
TabSheet3: TTabSheet;
DBNavigator1: TDBNavigator;
DBGrid2: TDBGrid;
DataSource2: TDataSource;
Button2: TButton;
DBNavigator2: TDBNavigator;
DBGrid3: TDBGrid;
Panel1: TPanel;
DataSource3: TDataSource;
Button3: TButton;
TabSheet4: TTabSheet;
XPManifest1: TXPManifest;
Button4: TButton;
MainMenu1: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N6: TMenuItem;
N3: TMenuItem;
N7: TMenuItem;
N8: TMenuItem;
N9: TMenuItem;
About1: TMenuItem;
N10: TMenuItem;
N11: TMenuItem;
N12: TMenuItem;
N13: TMenuItem;
N14: TMenuItem;
DBGrid4: TDBGrid;
Edit1: TEdit;
IBQuery1: TIBQuery;
DataSource4: TDataSource;
procedure Button4Click(Sender: TObject);
procedure N12Click(Sender: TObject);
procedure N6Click(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses Unit3, Unit1, Unit4, Unit5, Unit6;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.Show;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
try
DataSource1.DataSet.Delete;
except
ShowMessage('Нельзя удалить данные о клиенте если в таблице База есть связанные записи!');
end;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
Form4.Show;
end;
procedure TForm2.N3Click(Sender: TObject);
begin
Form2.Close;
end;
procedure TForm2.N4Click(Sender: TObject);
begin
Form5.Show;
Form5.Button1.Enabled:=true;
Form5.Panel2.Visible:=false;
Form5.Button3.Enabled:=false;
Form5.Button4.Enabled:=false;
end;
procedure TForm2.N6Click(Sender: TObject);
begin
Form6.Show;
end;
procedure TForm2.N12Click(Sender: TObject);
begin
Form5.Show;
Form5.Button1.Enabled:=false;
DataSource1.DataSet.Cancel;
DataSource1.DataSet.First;
Form5.Panel2.Visible:=true;
Form5.Button3.Enabled:=true;
Form5.Button4.Enabled:=true;
end;
procedure TForm2.Button4Click(Sender: TObject);
begin
if Edit1.Text <>'' then
begin
IbQuery1.SQL.Text:=Edit1.Text;
Form2.DataSource4.DataSet.Active:=true;
end
else ShowMessage('Пустой запрос!');
end;
end.
Unit4:
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, Grids, DBGrids, IBCustomDataSet;
type
TForm4 = class(TForm)
IBDataSet1: TIBDataSet;
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
DataSource1: TDataSource;
DataSource2: TDataSource;
CheckBox1: TCheckBox;
procedure CheckBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
uses Unit2, Unit3;
{$R *.dfm}
procedure TForm4.CheckBox1Click(Sender: TObject);
begin
if CheckBox1.State = cbchecked then
begin
DataModule3.IBDataSet1.Active:=False;
Form4.IBDataSet1.SelectSQL.SetText('SELECT * FROM DEAL WHERE CL_ID =:ID_C');
Form4.IBDataSet1.Open;
DataModule3.IBDataSet1.Open;
end else
begin
Form4.IBDataSet1.Close;
DataModule3.IBDataSet1.Close;
Form4.IBDataSet1.SelectSQL.SetText('SELECT * FROM DEAL');
Form4.IBDataSet1.Active:=True;
DataModule3.IBDataSet1.Active:=True;
end;
end;
end.
Unit5:
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, DBCtrls, Mask, DB, IBCustomDataSet;
type
TForm5 = class(TForm)
DBEdit1: TDBEdit;
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
DBMemo1: TDBMemo;
DataSource1: TDataSource;
Panel2: TPanel;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
procedure Button6Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormShow(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form5: TForm5;
implementation
uses Unit2, Unit4, Unit1, Unit3;
{$R *.dfm}
procedure TForm5.Button1Click(Sender: TObject);
var name,p:string;
begin
name:=DbEdit1.Text;
p:= DbMemo1.Text;
try
DataSource1.DataSet.FieldByName('FIO').AsString:=name;
DataSource1.DataSet.FieldByName('PASPORT').AsString:=p;
DataSource1.DataSet.Post;
DataSource1.DataSet.Append;
except
ShowMessage('Поле ФИО обязательно для заполнения');
end;
end;
procedure TForm5.Button2Click(Sender: TObject);
begin
DbEdit1.Clear;
DbMemo1.Clear;
end;
procedure TForm5.Button3Click(Sender: TObject);
begin
try
Form2.DataSource1.DataSet.Delete;
except
ShowMessage('Нельзя удалить данные о клиенте если в таблице База есть связанные записи!');
end;
end;
procedure TForm5.FormShow(Sender: TObject);
begin
DataSource1.DataSet.Append;
end;
procedure TForm5.FormClose(Sender: TObject; var Action: TCloseAction);
begin
DataSource1.DataSet.Cancel;
end;
procedure TForm5.Button4Click(Sender: TObject);
begin
Form2.DataSource1.DataSet.Post;
end;
procedure TForm5.Button5Click(Sender: TObject);
begin
Form2.DataSource1.DataSet.Prior;
end;
procedure TForm5.Button6Click(Sender: TObject);
begin
Form2.DataSource1.DataSet.Next;
end;
end.
Unit6:
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, DBCtrls, StdCtrls, IBCustomDataSet, IBQuery, Mask;
type
TForm6 = class(TForm)
DBLookupComboBox1: TDBLookupComboBox;
DataSource1: TDataSource;
Edit1: TEdit;
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
IBQuery1: TIBQuery;
DataSource2: TDataSource;
DBEdit1: TDBEdit;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form6: TForm6;
s:string;
implementation
uses Unit3;
{$R *.dfm}
procedure TForm6.FormShow(Sender: TObject);
begin
DataSource1.DataSet.Append;
end;
procedure TForm6.Button1Click(Sender: TObject);
var s: string;
begin
Form6.IBQuery1.Active:=false;
s:='select MONEY from movie where movie.id = '+ Edit1.Text;
Form6.IBQuery1.SQL.text:=s;
Form6.IBQuery1.Active:=true;
Form6.DBEdit1.DataField:='MONEY';
DataSource1.DataSet.FieldByName('DEN').AsString:=Form6.DBEdit1.Text;
DataSource1.DataSet.FieldByName('ID_M').AsString:=Edit1.Text;
DataSource1.DataSet.Post;
DataSource1.DataSet.Append;
end;
procedure TForm6.FormClose(Sender: TObject; var Action: TCloseAction);
begin
DataSource1.DataSet.Cancel;
end;
end.
Unit7:
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm7 = class(TForm)
ComboBox1: TComboBox;
Button1: TButton;
Edit1: TEdit;
ComboBox2: TComboBox;
procedure ComboBox2Change(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form7: TForm7;
tb,k:string;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm7.ComboBox1Change(Sender: TObject);
begin
if Combobox1.Items.Strings[Combobox1.ItemIndex]='Фильмы' then
begin
tb:='MOVIE';
Combobox2.Items.Clear;
Combobox2.Items.Add('ID');
Combobox2.Items.Add('NAME_FILM');
Combobox2.Items.Add('DIRECTOR');
Combobox2.Items.Add('KOL');
Combobox2.Items.Add('MONEY');
Combobox2.Items.Add('GANR');
Combobox2.Items.Add('DESCRIPTION');
end else
begin
tb:='CLIENT';
Combobox2.Items.Clear;
Combobox2.Items.Add('ID_C');
Combobox2.Items.Add('FIO');
Combobox2.Items.Add('PASPORT');
end;
if Combobox1.Items.Strings[Combobox1.ItemIndex]='Счета' then
begin
tb:='DEAL';
Combobox2.Items.Clear;
Combobox2.Items.Add('ID_D'); Combobox2.Items.Add('ID_M');
Combobox2.Items.Add('CL_ID'); Combobox2.Items.Add('DEN');
Combobox2.Items.Add('D_D');
end;
end;
procedure TForm7.Button1Click(Sender: TObject);
var
zapros: string;
begin
if (k = 'ID_C') or (k = 'ID') or (k = 'ID_D') or(k='KOL') or (k='MONEY') or(k='ID_M') or (k='CL_ID')
then
zapros:='SELECT * from '+tb+' where '+k+'='+Edit1.Text
else
zapros:='SELECT * from '+tb+' where '+k+' LIKE '+'''%'+Edit1.Text+'%''';
Form2.IBQuery1.SQL.Text:=zapros;
Form2.DataSource4.DataSet.Active:=true;
Form7.Close;
Form2.PageControl1.ActivePage:= Form2.PageControl1.Pages[4];
Form2.FocusControl(Form2.PageControl1);
end;
procedure TForm7.ComboBox2Change(Sender: TObject);
begin
k:=Combobox2.Items.Strings[Combobox2.ItemIndex];
end;
end.
Скрипты:
DOMAINS:
CREATE DOMAIN D_GANR AS
VARCHAR(10) CHARACTER SET NONE
NOT NULL
CHECK (VALUE IN ('comedy', 'action', 'melodramm', 'fantasy', 'horror'))
COLLATE NONE
Tables:
CLIENT:
/******************************************************************************/
/**** Tables ****/
/******************************************************************************/
CREATE GENERATOR GEN_CLIENT_ID_C;
CREATE TABLE CLIENT (
ID_C INTEGER,
FIO VARCHAR(50) NOT NULL,
PASPORT VARCHAR(50)
);
/******************************************************************************/
/**** Primary Keys ****/
/******************************************************************************/
ALTER TABLE CLIENT ADD PRIMARY KEY (ID_C);
/******************************************************************************/
/**** Triggers ****/
/******************************************************************************/
SET TERM ^;
/******************************************************************************/
/**** Triggers for tables ****/
/******************************************************************************/
/* Trigger: TRIG_CLIENT */
CREATE TRIGGER TRIG_CLIENT FOR CLIENT
ACTIVE BEFORE INSERT POSITION 0
AS BEGIN
IF (NEW.id_c IS NULL) THEN NEW.id_c = GEN_ID(gen_client_id_c,1);
END
^
DEAL:
/******************************************************************************/
/**** Tables ****/
/******************************************************************************/
CREATE GENERATOR GEN_DEAL_ID;
CREATE TABLE DEAL (
ID_D INTEGER,
ID_M INTEGER NOT NULL,
CL_ID INTEGER NOT NULL,
DEN NUMERIC(4,2),
D_D DATE
);
/******************************************************************************/
/**** Primary Keys ****/
/******************************************************************************/
ALTER TABLE DEAL ADD PRIMARY KEY (ID_D);
/******************************************************************************/
/**** Foreign Keys ****/
/******************************************************************************/
ALTER TABLE DEAL ADD FOREIGN KEY (CL_ID) REFERENCES CLIENT (ID_C) ON UPDATE CASCADE;
ALTER TABLE DEAL ADD FOREIGN KEY (ID_M) REFERENCES MOVIE (ID) ON DELETE CASCADE ON UPDATE CASCADE;
/******************************************************************************/
/**** Triggers for tables ****/
/******************************************************************************/
/* Trigger: DEC_MONEY */
CREATE TRIGGER DEC_MONEY FOR DEAL
ACTIVE AFTER INSERT POSITION 0
AS
declare variable x integer;
begin
Select Count(New.cl_id) from DEAL
into:x;
if (:x > 3) then
begin
update Deal
set Deal.den = (DEAL.den - DEAL.den/100*10)
where DEAL.id_d = New.id_d;
end
end
/* Trigger: SUB_MOVIE */
CREATE TRIGGER SUB_MOVIE FOR DEAL
ACTIVE AFTER INSERT POSITION 0
AS
begin
update movie
set movie.kol = movie.kol - 1
where movie.id = new.id_m;
end
/* Trigger: TRIG_DEAL_BI */
CREATE TRIGGER TRIG_DEAL_BI FOR DEAL
ACTIVE BEFORE INSERT POSITION 0
AS BEGIN
IF (NEW.Id_d IS NULL) THEN NEW.Id_d = GEN_ID(Gen_DEAL_ID,1);
END
MOVIE:
/******************************************************************************/
/**** Tables ****/
/******************************************************************************/
CREATE GENERATOR GEN_DEAL_ID;
CREATE TABLE DEAL (
ID_D INTEGER,
ID_M INTEGER NOT NULL,
CL_ID INTEGER NOT NULL,
DEN NUMERIC(4,2),
D_D DATE
);
/******************************************************************************/
/**** Primary Keys ****/
/******************************************************************************/
ALTER TABLE DEAL ADD PRIMARY KEY (ID_D);
/******************************************************************************/
/**** Foreign Keys ****/
/******************************************************************************/
ALTER TABLE DEAL ADD FOREIGN KEY (CL_ID) REFERENCES CLIENT (ID_C) ON UPDATE CASCADE;
ALTER TABLE DEAL ADD FOREIGN KEY (ID_M) REFERENCES MOVIE (ID) ON DELETE CASCADE ON UPDATE CASCADE;
/******************************************************************************/
/**** Triggers for tables ****/
/******************************************************************************/
/* Trigger: DEC_MONEY */
CREATE TRIGGER DEC_MONEY FOR DEAL
ACTIVE AFTER INSERT POSITION 0
AS
declare variable x integer;
begin
Select Count(cl_id) from DEAL where cl_id = New.cl_id group by cl_id
into:x;
if (:x > 3) then
begin
update Deal
set Deal.den = (DEAL.den - DEAL.den/100*10)
where DEAL.id_d = New.id_d;
end
end
/* Trigger: SUB_MOVIE */
CREATE TRIGGER SUB_MOVIE FOR DEAL
ACTIVE AFTER INSERT POSITION 0
AS
begin
update movie
set movie.kol = movie.kol - 1
where movie.id = new.id_m;
end
/* Trigger: TRIG_DEAL_BI */
CREATE TRIGGER TRIG_DEAL_BI FOR DEAL
ACTIVE BEFORE INSERT POSITION 0
AS BEGIN
IF (NEW.Id_d IS NULL) THEN NEW.Id_d = GEN_ID(Gen_DEAL_ID,1);
END
EXCEPTION:
CREATE EXCEPTION NO_DELETE 'Нельзя удалить фильм если он имеется на складе!';
VIEW:
CREATE VIEW BESTCLIENT(FIO)
AS
select FIO from client where id_c =(select cl from(select deal.cl_id as cl, count (cl_id) as col from deal group by deal.cl_id HAVING count (cl_id) >=All (select count (cl_id) as col from deal group by deal.cl_id)));
... данных предприятия, отношения, запросы. К зачету по вычислительной практике необходимо предоставить дискету с выполненной работой. Зачет по практике принимается руководителем практики от кафедры. 5. ЗАДАНИЯ НА ПРАКТИКУ 1 Разработать концептуальную схему базы данных для одной из следующих предметных областей (представить первую, вторую и третью нормальные формы отношений) согласно ...
... или текстовой информации, а также сделать реальной задачу обеспечения высокой достоверности обработки и хранения больших объемов данных. [6] 2. Проектная часть курсовой работы 2.1 Описание предметной области задачи Функционирование организации по продаже канцелярских товаров: ООО "КТ" осуществляет продажу канцелярских товаров. Хранится следующая информация о предприятиях-клиентах: ...
... -рекламная деятельность (издание книг, статей, буклетов о городе, его достопримечательностях); Мероприятия по реализации проекта: подготовка учредительной документации Клуба-музея фольклора; регистрация Клуба в качестве муниципального культурно - досугового учреждения. В работе использованы материалы периодической печати, ...
... Организация данных является ключевым моментом при работе с большими объемами информации. Чрезвычайно важно упорядочить информацию таким образом, чтобы легко и быстро находить нужные сведения. В Microsoft Access подлежащая хранению информация называется данными, а место ее хранения - базой данных. Перед созданием базы данных необходимо ответить на следующие вопросы. Каково назначение базы данных
0 комментариев