Работа с базами данных
Создание базы данных о продаваемых товарах и покупателях для отслеживания отпуска товаров со склада, а также автоматическим расчетом стоимости покупки. Администрирование базы данных. Создание псевдонима. Инструментальные средства баз данных Borland.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 06.05.2011 |
Размер файла | 798,7 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
1
Размещено на http://www.allbest.ru/
1. База данных (условной) предметной области
Рассмотрим учебную базу данных, которая будет служить иллюстрацией для построения различных примеров в дальнейшем. Пусть имеются следующие три таблицы:
Таблица 1. Товары
Код товара Integer
Наименование товара VarChar(20)
Единица измерения VarChar(10)
Цена за единицу Integer
Количество товара на складе Integer
Таблица 2. Покупатели
Код покупателя Integer
Наименование покупателя VarChar(30)
Город VarChar(15)
Адрес VarChar(20)
Телефон VarChar(10)
Таблица 3. Расход товара
Код покупки Integer
Дата покупки Date
Количество покупки Integer
Стоимость покупки Integer
Код товара Integer
Код покупателя Integer
Первая таблица содержит сведения о продаваемых товарах - наименование, в каких единицах измеряется товар, цена единицы товара и количество товара на складе на момент просмотра таблицы. Для простоты предполагается, что цена товара не меняется со временем. Наименование полностью идентифицирует товар. Если один и тот же товар присутствует на складе в разных единицах измерения, то он должен иметь семантически одинаковое, но синтаксически разное название (например, огурцы баночные, огурцы развесные и пр.). Однако для однозначной идентификации товара используется специальный код товара. Именно код товара будем считать первичным ключом в таблице «Товары».
Таблица 2 содержит данные о покупателях товара. Столбец «город» выделен из столбца «адрес» для дальнейших упражнений по составлению запросов.
Третья таблица предназначена для отслеживания отпуска товаров со склада конкретным покупателям. Каждый день на склад поступают товары. Допустим, что процесс прихода товаров на склад и его учет нас не интересуют (на самом деле наш пример является составной частью большой задачи). Таблица «Расход товара» является дочерней для таблиц «Товары» и «Покупатели» и находится с ними в связи многие к одному. Поэтому между дочерней таблицей и каждой из ее родительских таблиц должно выполняться требование ссылочной целостности - отпускаемые товары должны присутствовать в таблице «Товары», а получающие их покупатели - в таблице «Покупатели». Стоимость покупки определяется произведением цены товара на количество купленного товара.
2. Создание базы данных. Работа с InterBase WINDOWS IB_CONSOLE
Создадим базу данных в INTERBASE, состоящую из описанных выше таблиц. Для хранения базы данных используется папка «C:\UCHBASE\SKLAD» (эту папку следует предварительно создать). Для создания базы данных воспользуемся утилитой INTERBASE WINDOWS IB_CONSOLE. Перед началом работы необходимо проверить, запущен ли сервер INTERBASE. По умолчанию, при инсталляции, сервер настраивается на автоматический запуск (если сервер запущен, на панели задач появляется соответствующее изображение ярлыка). Если сервер по какой-либо причине не запущен, необходимо это сделать в ручном режиме с использованием утилиты INTERBASE MANAGER.
Если работа с утилитой INTERBASE WINDOWS IB_CONSOLE происходит в первый раз, необходимо зарегистрировать сервер (это делается только один раз). После появления рабочего окна программы необходимо вызвать контекстное меню и выбрать строку регистрации. В появившемся диалоговом окне заполняется имя пользователя (системное имя SYSDBA) и пароль. Позиция «Local Server» означает создание локальной базы данных на Вашем компьютере (позиция «Remote Server» выбирается при создании удаленной базы данных). Если сервер зарегистрирован в системе, то работа в IB_CONSOLE начинается с установления связи с сервером путем выбора пункта Login. Далее необходимо набрать имя пользователя и пароль. Завершение работы с сервером (разрыв связи) происходит путем выбора режима LogOut.
Для создания базы данных необходимо в позиции DATABASE, нажав на правую кнопку мыши, выбрать строку Create DataBase с вызовом на экран следующего диалогового окна:
В пункте Alias необходимо набрать идентификатор пользователя, в таблице Files указать полный путь к базе данных (с расширением.gdb для базы INTERBASE, в данном примере база содержится в одном файле), в позиции Default Character Set выбрать кодовую страницу WIN1251 для поддержки русского языка. Остальные параметры можно сохранить по умолчанию. Следует обратить внимание на позицию SQL Dialect. Однажды выбрав диалект языка, необходимо поддерживать именно этот вариант во время работы с базой данных (например, при переносе базы на другие компьютеры). Несоблюдение этого правила может приводить к различным проблемам при работе с базой данных. Завершение процедуры создания базы данных осуществляется нажатием на кнопку OK. В результате на экране появится информация о пустой базе данных.
В статус строке в нижней части экрана высвечивается информация о соединении с базой данных (что в данном случае означает, что база данных успешно создана). В правой части экрана выдается список возможных действий пользователя при работе с базой данных. Он включает возможности архивации и разархивации базы данных (BackUp, Restore), просмотра статистической информации о базе данных (Statistics), выключения сервера (ShutDown), отсоединения от сервера (Disconnect), просмотра в текстовом виде текущего состояния базы данных (View Metadata). Информацию о структуре таблиц базы данных, индексах, связях между таблицами и хранимых процедурах на текущий момент времени можно сохранить в текстовом файле с расширением.txt или.sql. Эта информация может быть использована в дальнейшем для восстановления структуры базы данных и создания отчетов.
При условии, что база данных создана на другом компьютере, ее необходимо зарегистрировать. Ниже приведен пример диалогового окна регистрации базы данных. Внимание! При регистрации необходимо указать кодовую таблицу для базы данных (несмотря на то, что она указывается при создании базы данных).
Следующий шаг состоит в создании таблиц в составе базы данных. Для создания таблиц необходимо использовать операторы языка SQL. Вызов режима работы с операторами языка SQL производится через пункты меню tools\interactive SQL….
На рисунке приведен пример такого оператора для создания структуры таблицы «Товары» создаваемой базы данных.
Кнопка используется для проверки синтаксиса набранного оператора SQL. Запуск оператора в диалоговом окне осуществляется нажатием на кнопку . После выполнения оператора в базе данных создается таблица TOVARY, ее поля соответственно получают наименования KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV. Параметр NOT NULL вводится для контроля начального заполнения поля при его обработке (в этом случае, если поле не получило никакого значения, на уровне сервера вырабатывается исключительная ситуация; мы сознательно не поставили этот параметр на полях ED_IZM и COUNT_TOV для демонстрации обработки соответствующей ситтуации на уровне клиентского места). Кроме того, параметр DEFAULT задает значение соответствующего поля по умолчанию. Поскольку поле ZENA не может принимать отрицательных значений, то для этого поля определен предикат ZENA >= 0, исполняющий роль сторожа. Ложное значение предиката генерирует исключительную ситуацию. Поле COUNT_TOV также должно принимать неотрицательные значения. При проектировании базы данных проверка этого предиката оставлена клиентской части программы. Параметр COLLATE определяет порядок сортировки символьных полей. В данном примере для символьных полей TOVAR и ED_IZM определен порядок сортировки символов русской кириллицы. Для таблицы TOVARY определен первичный ключ KOD_TOVAR.
В случае ошибки выполнения оператора генерируется соответствующий код ошибки, о чем сообщается пользователю. Текст последнего выполненного оператора можно вернуть, нажав на кнопку . Интерактивную справку по операторам SQL можно получить через меню Help\SQL References. SQL операторы могут быть загружены (сохранены) из текстового файла с расширением.sql (режимы Load Sсript и Save Sсript)
Перед созданием таблицы «Покупатели» создадим домен KEY_TYPE, используя оператор:
CREATE DOMAIN KEY_TYPE AS INTEGER DEFAULT 0 NOT NULL;
Использование домена предпочтительно в том случае, когда в базе данных присутствуют различные столбцы, обладающие одними и теми же характеристиками.
Таблица «Покупатели» определяется оператором:
CREATE TABLE POKUPATELI (
KOD_POKUP KEY_TYPE,
POKUP VARCHAR(30) NOT NULL COLLATE PXW_CYRL,
GOROD VARCHAR(20) DEFAULT '' COLLATE PXW_CYRL,
ADRES VARCHAR(25) DEFAULT '' COLLATE PXW_CYRL,
TEL VARCHAR(8) COLLATE PXW_CYRL,
PRIMARY KEY (KOD_POKUP));
Отметим, что при определении поля KOD_POKUP используется ранее определенный домен KEY_TYPE. Для таблицы определен первичный ключ KOD_POKUP.
Таблица «РАСХОД ТОВАРА» определяется оператором:
CREATE TABLE RASXOD (
KOD_RASH KEY_TYPE,
DATA_RASH TIMESTAMP NOT NULL,
KOLVO INTEGER DEFAULT 0,
STOIM KEY_TYPE,
KOD_TOVAR KEY_TYPE,
KOD_POKUP KEY_TYPE,
PRIMARY KEY (KOD_RASH));
Поскольку в нашей задаче существует связь между таблицами (каждая покупка, описанная в таблице RASXOD связывает конкретного покупателя, описанного в таблице POKUPATELI с товаром, описание которого дано в таблице TOVARY), необходимо зафиксировать эту связь на уровне базы данных. Отсутствие такой информации может привести к ситуации, когда зафиксирована покупка отсутствующего товара, или товар приобретен не зафиксированным покупателем. Поддержка концепции целостности данных обеспечивается установкой специальных связей.
Добавим связи между таблицами
ALTER TABLE RASXOD
ADD CONSTRAINT TOV_RASH
FOREIGN KEY (KOD_TOVAR) REFERENCES TOVARY
ON DELETE CASCADE ON UPDATE CASCADE;
В базу данных добавлена связь таблицы «Расход» по полю KOD_TOVAR с родительской таблицей «Товары». Теперь InterBase SQL-сервер не допустит появления в таблице «Расход» строк со значениями поля KOD_TOVAR, которые не встречаются в таблице «Товары». Причем, благодаря дополнительным указаниям ON…, удаление товара или изменение кода товара в таблице «Товары» повлечет соответствующие изменения в соответствующих записях дочерней таблицы «Расход» (режим каскадного обновления содержимого таблиц).
Связь между таблицами «Расход» и «Покупатели» определим следующим оператором:
ALTER TABLE RASXOD
ADD CONSTRAINT POK_RASH
FOREIGN KEY (KOD_POKUP) REFERENCES POKUPATELI;
В этом случае не объявлено автоматическое каскадное обновление и удаление записей дочерней таблицы для соответствующих операций в родительской таблице. По умолчанию будет использована RESTRICT-стратегия поддержания ссылочной целостности, т.е. SQL-сервер не допустит удаления строки и изменения кода покупателя таблице «Покупатели», если на этого покупателя (по коду) ссылается хотя бы одна строка таблицы «Расход». Программист может запрограммировать соответствующие действия каскадного обновления и удаления в процедурах-триггерах базы данных.
Соответствующие триггеры выглядят следующим образом.
Для обновления дочерней таблицы
CREATE TRIGGER AU_POKUPATELI FOR POKUPATELI
ACTIVE AFTER UPDATE POSITION 0
AS
BEGIN
IF (OLD.KOD_POKUP <> NEW.KOD_POKUP) THEN
UPDATE RASXOD
SET KOD_POKUP=NEW.KOD_POKUP
WHERE KOD_POKUP = OLD.KOD_POKUP;
END
Триггер - это процедура, которая выполняется автоматически при изменениях, происходящих в таблице. В данном случае триггер будет выполняться после изменений (AFTER UPDATE) в таблице POKUPATELI и выполнит соответствующие изменения в дочерней таблице RASXOD, если изменилось значение родительского ключа (первичного ключа родительской таблицы). Аббревиатура AU в названии триггера построена из символов А(AFTER) и U(UPDATE). OLD.KOD_POKUP и NEW.KOD_POKUP - это старое и новое значения поля KOD_POKUP в таблице POKUPATELI. Перед тем как обновлять таблицу RASXOD триггер проверяет изменилось ли значение поля KOD_POKUP в таблице POKUPATELI. Данная проверка оптимизирует работу сервера (любые изменения в таблице RASXOD связаны с просмотром всей таблицы, что чревато большими накладными расходами при большом объеме таблицы). Заметим, что все SQL-операторы в WINDOWS IB_CONSOLE должны завершаться точкой с запятой.
Аналогичный триггер для события удаления записей выглядит следующим образом:
CREATE TRIGGER AD_POKUPATELI FOR POKUPATELI
ACTIVE AFTER DELETE AS
BEGIN
DELETE FROM RASXOD
WHERE RASXOD.KOD_POKUP = POKUPATELI.KOD_POKUP;
END
Теперь при удалении покупателя или изменении кода покупателя в таблице POKUPATELI соответствующие каскадные изменения произойдут в дочерней таблице RASXOD.
Следует отметить, что таблицы «Товары» и «Расход товара» связаны по формулам:
Стоимость купленного товара:= Количество купленного товара * цена единицы товара;
Количество товара на складе:= Количество товара на складе - Количество купленного товара.
Эти соотношения тоже являются требованиями целостности (правильности) базы данных, однако имеют специальный связанный с конкретной предметной областью характер. Контроль первого требования оставим клиентской части программы.
Решение второй задачи возложим на SQL-сервер. Для этого добавим в БД триггер, отрабатывающий после ввода новых данных в таблицу RASXOD
CREATE TRIGGER AI_RASXOD1 FOR RASXOD
ACTIVE AFTER INSERT POSITION 1 AS
BEGIN
UPDATE TOVARY
SET COUNT_TOV = COUNT_TOV-NEW.KOLVO
WHERE KOD_TOVAR = NEW.KOD_TOVAR;
END
Триггер, отрабатывающий перед удалением данных в таблице RASXOD, выглядит следующим образом
CREATE TRIGGER BD_RASXOD1 FOR RASXOD
ACTIVE BEFORE DELETE POSITION 0 AS
BEGIN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+RASXOD.KOLVO
WHERE KOD_TOVAR = RASXOD.KOD_TOVAR;
END
Триггер, отрабатывающий после обновления данных в таблице RASXOD (а точнее при изменении количества купленного товара)
CREATE TRIGGER AU_RASXOD1 FOR RASXOD
ACTIVE AFTER UPDATE POSITION 1 AS
BEGIN
IF ((OLD.KOLVO <> NEW.KOLVO) AND
(OLD.KOD_TOVAR = NEW.KOD_TOVAR)) THEN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+OLD.KOLVO-NEW.KOLVO
WHERE KOD_TOVAR = OLD.KOD_TOVAR;
END;
Остается еще один не рассмотренный случай - изменение кода купленного товара KOD_TOVAR в строке таблицы RASXOD должно повлечь перерасчет значений количества товаров на складе COUNT_TOV в таблице TOVARY.
CREATE TRIGGER AU_RASXOD0 FOR RASXOD
ACTIVE AFTER UPDATE POSITION 0 AS
DECLARE VARIABLE OldKod INTEGER;
BEGIN
IF (OLD.KOD_TOVAR <> NEW.KOD_TOVAR) THEN
BEGIN OldKod = NULL;
SELECT KOD_TOVAR FROM TOVARY
WHERE KOD_TOVAR = OLD.KOD_TOVAR
INTO: OldKod;
IF (OldKod IS NOT NULL) THEN
BEGIN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+OLD.KOLVO
WHERE KOD_TOVAR = OLD.KOD_TOVAR;
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV-NEW.KOLVO
WHERE KOD_TOVAR = NEW.KOD_TOVAR;
END
END
END
Комментарий к триггерам обновления:
Вообще-то можно было бы написать один триггер обновления, подходящим образом объединив их содержание. Но раз уж их два, то возникает вопрос об их взаимоотношениях:
После события обновления таблицы RASXOD (FOR RASXOD AFTER UPDATE) отработают оба триггера.
Порядок, в котором они отработают, задан предложением POSITION n. Правда, в нашем случае этот порядок не важен.
Однако важно, чтобы только один из них внес изменения в таблицу TOVARY, поэтому в теле использованы альтернативные IF-условия.
В триггере AU_RASXOD0 используется еще одно (внутреннее) IF-условие и связанный с ним оператор SELECT.
Это IF-условие связано со спецификой триггеров - в отличие от обычных процедур триггер вызывается не оператором процедуры, а неявно по соответствующему событию, что достаточно необычно для традиционного процедурного программирования. Поэтому программирование триггеров требует специального внимания - дабы не допустить действий, просто лишних, а тем более искажающих результат или ведущих к порочному кругу (Deadlock).
В нашем случае, если в таблице «Товары» изменится значение поля KOD_TOVAR, то в дочерней таблице «Расход» будет выполнено каскадное обновление согласно объявленному ограничению ссылочной целостности. Это обновление инициирует запуск всех UPDATE-триггеров таблицы RASXOD… для каждой обновляемой её строки… Далее можно просчитать, что такой косвенный вызов не должен повлечь перерасчета количества товаров на складе в таблице «Товары»… а он произойдет и даст неправильный результат…
SELECT-оператор и последующее IF-условие позволяют проверить, имеется ли OLD.KOD_TOVAR в таблице TOVARY… отсутствовать он может только в случае косвенного вызова триггера AU_RASXOD0, инициированного тем самым каскадным обновлением. Возможно, это не самое лучшее решение проблемы, но решение…
Каждая таблица имеет первичный ключ - целочисленное поле. Значения такого поля для различных записей должны быть разными по определению. Поскольку это поле не имеет содержательного смысла и используется только для связи между таблицами, то заполнение этого поля (проверку уникальности его значения) можно поручить серверу базы данных. Для этого удобно использовать генераторы.
Генератор - это переменная, значение которой хранится в БД, поэтому оно не теряется при завершении работы программы и восстанавливается при повторном ее запуске. Создается генератор посредством оператора
CREATE GENERATOR TOVARY_KOD;
Инициализация генератора производится оператором
SET GENERATOR TOVARY_KOD TO 100;
Соответствующие операторы для таблиц POKUPATELI и RASXOD выглядят следующим образом:
CREATE GENERATOR POKUPATELI_KOD;
SET GENERATOR POKUPATELI_KOD TO 100;
CREATE GENERATOR RASXOD_KOD;
SET GENERATOR RASXOD_KOD TO 100;
Далее необходимо определить хранимые процедуры, изменяющие на 1 значения этих переменных.
CREATE PROCEDURE GET_KOD_TOVAR
RETURNS (NR INTEGER) AS
BEGIN NR=GEN_ID (TOVARY_KOD, 1); END
CREATE PROCEDURE GET_KOD_POKUP
RETURNS (NR INTEGER) AS
BEGIN NR=GEN_ID (POKUPATELI_KOD, 1); END
CREATE PROCEDURE GET_KOD_RASXOD
RETURNS (NR INTEGER) AS
BEGIN NR=GEN_ID (RASXOD_KOD, 1); END
В результате наших действий на сервере формируется следующая база:
/* Extract Database c:\uchbase\sklad\ib_sklad.gdb */
CREATE DATABASE «c:\uchbase\sklad\ib_sklad.gdb» PAGE_SIZE 1024
DEFAULT CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN KEY_TYPE AS INTEGER DEFAULT 0 NOT NULL;
/* Table: POKUPATELI, Owner: SYSDBA */
CREATE TABLE POKUPATELI (KOD_POKUP KEY_TYPE,
POKUP VARCHAR(30) CHARACTER SET WIN1251 NOT NULL COLLATE PXW_CYRL,
GOROD VARCHAR(20) CHARACTER SET WIN1251 DEFAULT ''
COLLATE PXW_CYRL,
ADRES VARCHAR(25) CHARACTER SET WIN1251 DEFAULT ''
COLLATE PXW_CYRL,
TEL VARCHAR(8) CHARACTER SET WIN1251 COLLATE PXW_CYRL,
PRIMARY KEY (KOD_POKUP));
/* Table: RASXOD, Owner: SYSDBA */
CREATE TABLE RASXOD (KOD_RASH KEY_TYPE,
DATA_RASH TIMESTUMP NOT NULL,
KOLVO INTEGER DEFAULT 0,
STOIM KEY_TYPE,
KOD_TOVAR KEY_TYPE,
KOD_POKUP KEY_TYPE,
PRIMARY KEY (KOD_RASH));
/* Table: TOVARY, Owner: SYSDBA */
CREATE TABLE TOVARY (KOD_TOVAR INTEGER NOT NULL,
TOVAR VARCHAR(20) CHARACTER SET WIN1251 NOT NULL COLLATE PXW_CYRL,
ED_IZM VARCHAR(10) CHARACTER SET WIN1251 DEFAULT ''
COLLATE PXW_CYRL,
ZENA INTEGER DEFAULT 0,
COUNT_TOV INTEGER,
PRIMARY KEY (KOD_TOVAR));
ALTER TABLE RASXOD ADD CONSTRAINT TOV_RASH FOREIGN KEY (KOD_TOVAR) REFERENCES TOVARY (KOD_TOVAR) ON UPDATE CASCADE ON DELETE CASCADE;
ALTER TABLE RASXOD ADD CONSTRAINT POK_RASH FOREIGN KEY (KOD_POKUP) REFERENCES POKUPATELI (KOD_POKUP);
CREATE GENERATOR TOVARY_KOD;
CREATE GENERATOR POKUPATELI_KOD;
CREATE GENERATOR RASXOD_KOD;
ALTER TABLE TOVARY ADD
CHECK (ZENA >= 0);
COMMIT WORK;
SET AUTODDL OFF;
SET TERM ^;
/* Stored procedures */
CREATE PROCEDURE GET_KOD_POKUP AS BEGIN EXIT; END ^
CREATE PROCEDURE GET_KOD_RASXOD AS BEGIN EXIT; END ^
CREATE PROCEDURE GET_KOD_TOVAR AS BEGIN EXIT; END ^
ALTER PROCEDURE GET_KOD_POKUP RETURNS (NR INTEGER) AS
BEGIN NR=GEN_ID (POKUPATELI_KOD, 1);
END
^
ALTER PROCEDURE GET_KOD_RASXOD RETURNS (NR INTEGER) AS
BEGIN
NR=GEN_ID (RASXOD_KOD, 1);
END
^
ALTER PROCEDURE GET_KOD_TOVAR RETURNS (NR INTEGER) AS
BEGIN
NR=GEN_ID (TOVARY_KOD, 1);
END
^
SET TERM; ^
COMMIT WORK;
SET AUTODDL ON;
SET TERM ^;
/* Triggers only will work for SQL triggers */
CREATE TRIGGER AU_POKUPATELI FOR POKUPATELI
ACTIVE AFTER UPDATE POSITION 0 AS
BEGIN
IF (OLD.KOD_POKUP <> NEW.KOD_POKUP) THENUPDATE RASXOD SET KOD_POKUP=NEW.KOD_POKUP WHERE KOD_POKUP = OLD.KOD_POKUP; END
^
CREATE TRIGGER AD_POKUPATELI FOR POKUPATELI
ACTIVE AFTER DELETE POSITION 0 AS
BEGIN
DELETE FROM RASXOD
WHERE RASXOD.KOD_POKUP = POKUPATELI.KOD_POKUP;
END
^
CREATE TRIGGER AI_RASXOD1 FOR RASXOD
ACTIVE AFTER INSERT POSITION 1 AS
BEGIN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV-NEW.KOLVO
WHERE KOD_TOVAR = NEW.KOD_TOVAR;
END
^
CREATE TRIGGER AU_RASXOD1 FOR RASXOD
ACTIVE AFTER UPDATE POSITION 1 AS
BEGIN
IF ((OLD.KOLVO <> NEW.KOLVO) AND
(OLD.KOD_TOVAR = NEW.KOD_TOVAR)) THEN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+OLD.KOLVO-NEW.KOLVO
WHERE KOD_TOVAR = OLD.KOD_TOVAR;
END
^
CREATE TRIGGER BD_RASXOD1 FOR RASXOD
ACTIVE BEFORE DELETE POSITION 0 AS
BEGIN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+RASXOD.KOLVO
WHERE KOD_TOVAR = RASXOD.KOD_TOVAR;
END
^
CREATE TRIGGER AU_RASXOD0 FOR RASXOD
ACTIVE AFTER UPDATE POSITION 0 AS
DECLARE VARIABLE OldKod INTEGER;
BEGIN
IF (OLD.KOD_TOVAR <> NEW.KOD_TOVAR) THEN
BEGIN OldKod = NULL;
SELECT KOD_TOVAR FROM TOVARY
WHERE KOD_TOVAR = OLD.KOD_TOVAR
INTO: OldKod;
IF (OldKod IS NOT NULL) THEN
BEGIN
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV+OLD.KOLVO
WHERE KOD_TOVAR = OLD.KOD_TOVAR;
UPDATE TOVARY
SET COUNT_TOV= COUNT_TOV-NEW.KOLVO
WHERE KOD_TOVAR = NEW.KOD_TOVAR;
END
END
END
^
COMMIT WORK ^
SET TERM; ^
/* Grant permissions for this database */
При завершении работы в WINDOWS IB_CONSOLE необходимо зафиксировать изменения в базе данных, выбрав пункт меню «TRANSACTION > COMMIT». Выбор пункта меню TRANSACTION > ROLLBACK» приведет к отказу от всех изменений, произведенных в текущем сеансе работы (после последнего COMMIT).
Заполнение данных в таблице может быть выполнено в двух режимах:
1. Заполнение записей таблицы в интерактивном режиме с использованием средств IB CONSOLE. Для этого необходимо вызвать на экран интерактивное окно свойств соответствующей таблицы и, щелкнув на вкладке Data, начать набор данных. При вводе данных отрабатывают все триггера, определенные в базе данных.
2. Другим вариантом заполнения таблицы является использование операторов языка SQL. Для этого (используя любой редактор текстов, например WordPad) подготовим SQL-программу (SQL-Script) (см. файл ..\TBLOAD.SQL) и выполним ее в окне Interactive SQL (пункт меню Qwery > LOAD Script).
По
Ниже приведен протокол работы этой программы:
SET NAMES WIN1251;
CONNECT 'SKLAD\Ib_sklad.gdb'
USER 'SYSDBA' PASSWORD 'masterkey';
DELETE FROM RASXOD;
DELETE FROM POKUPATELI;
DELETE FROM TOVARY;
SELECT * FROM POKUPATELI;
INSERT INTO POKUPATELI (KOD_POKUP, POKUP, GOROD, ADRES, TEL)
VALUES (1,'Алиса', 'Казань', 'ул. Латышских стрелков', '92-45-67');
INSERT INTO POKUPATELI (KOD_POKUP, POKUP, GOROD, ADRES, TEL)
VALUES (2,'Буратино', 'Рим', 'Италия', '23-45-35');
INSERT INTO POKUPATELI (KOD_POKUP, POKUP, GOROD, ADRES, TEL)
VALUES (5,'Тротилла', 'Пруд', 'Италия', NULL);
INSERT INTO POKUPATELI (KOD_POKUP, POKUP, GOROD, ADRES, TEL)
VALUES (6,'Шекспир', 'Лондон', 'Англия', NULL);
SELECT * FROM POKUPATELI;
KOD_POKUP POKUP GOROD ADRES TEL
1 Алиса Казань ул. Латышских стрелков 92-45-67
2 Буратино Рим Италия 23-45-35
5 Тротилла Пруд Италия <null>
6 Шекспир Лондон Англия <null>
SELECT * FROM TOVARY;
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (1,'Сахар', 'кг', 12,1442);
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (2,'Макароны', 'кг', 5,86);
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (3,'Огурцы весовые', 'кг', 6,250);
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (4,'Огурцы баночные', 'банки', 10,475);
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (5,'Крупа манная', 'кг', 8,1010);
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (2,'Масло подсолнечное', 'л', 10,1977);
Statement failed, SQLCODE = -803
violation of PRIMARY or UNIQUE KEY constraint «INTEG_4» on table «TOVARY»
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (6,'Масло подсолнечное', 'л', - 10,1977);
Statement failed, SQLCODE = -297
Operation violates CHECK constraint INTEG_3 on view or table TOVARY
INSERT INTO TOVARY (KOD_TOVAR, TOVAR, ED_IZM, ZENA, COUNT_TOV)
VALUES (6,'Масло подсолнечное', 'л', 10,1977);
SELECT * FROM TOVARY;
KOD_TOVAR TOVAR ED_IZM ZENA COUNT_TOV
1 Сахар кг 12 1442
2 Макароны кг 5 86
3 Огурцы весовые кг 6 250
4 Огурцы баночные банки 10 475
5 Крупа манная кг 8 1010
6 Масло подсолнечное л 10 1977
SELECT * FROM RASXOD;
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (2,'12.04.98', 10,120,1,6);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (5,'12.07.00', 12,120,4,5);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (6,'13.09.00', 5,25,2,2);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (11,'12.04.03', 10,50,2,6);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (7,'15.09.00', 1,10,6,6);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (8,'16.07.00', 7,70,6,1);
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (9,'23.05.00', 11,110,400,1);
Statement failed, SQLCODE = -530
violation of FOREIGN KEY constraint «TOV_RASH» on table «RASXOD»
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (9,'23.05.00', 11,110,4,100);
Statement failed, SQLCODE = -530
violation of FOREIGN KEY constraint «POK_RASH» on table «RASXOD»
INSERT INTO RASXOD (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (9,'23.05.00', 11,110,4,1);
SELECT * FROM RASXOD;
KOD_RASH DATA_RASH KOLVO STOIM KOD_TOVAR KOD_POKUP
2 12-APR-1998 10 120 1 6
5 12-JUL-2000 12 120 4 5
6 13-SEP-2000 5 25 2 2
11 12-APR-2003 10 50 2 6
7 15-SEP-2000 1 10 6 6
8 16-JUL-2000 7 70 6 1
9 23-MAY-2000 11 110 4 1
SELECT * FROM TOVARY;
KOD_TOVAR TOVAR ED_IZM ZENA COUNT_TOV
1 Сахар кг 12 1432
2 Макароны кг 5 71
3 Огурцы весовые кг 6 250
4 Огурцы баночные банки 10 452
5 Крупа манная кг 8 1010
6 Масло подсолнечное л 10 1969
EXIT;
Отметим, что в процессе работы этой программы SQL-сервер проверял описанные ограничения целостности БД и прерывал выполнение операторов, которые нарушали эти ограничения:
Первое сообщение об ошибке (Statement failed…) связано с попыткой вставить в таблицу TOVARY строку с ключом (KOD_TOVAR=2), который уже был использован во второй строке.
Второе сообщение связано с попыткой вставить в таблицу TOVARY строку со значением поля ZENA=-10, для которого объявлен предикат CHECK (ZENA>=0).
Следующие два сообщения связаны с попытками нарушить требование межтабличной целостности - вставить в таблицу RASXOD строки с кодом товара (KOD_TOVAR=400) и кодом покупателя (KOD_POKUP=100), которые не встречаются в таблицах TOVARY и POKUPATELI, соответственно.
Отметим, что после загрузки данных в таблицу RASXOD содержимое таблицы TOVARY тоже изменилось (значение поля COUNT_TOV в некоторых записях) - это отрабатывал триггер AI_RASXOD1.
Остальные триггеры не отрабатывали, поскольку не происходили события их запускающие.
Не выполнялись также и хранимые процедуры, связанные с генераторами. В отличие от триггеров, хранимые процедуры вызываются явно оператором процедуры, а таковых в нашей программе не было. Кстати, именно в связи с этим выше рекомендована инициализация генераторов значением 100 (например, SET GENERATOR TOVARY_KOD TO 100;), так зарезервировано некое число кодов для установки в обход типового случая.
Теперь определим представление (View) для пользователей, которых интересуют покупки только не Казанских покупателей. Для этого опять подготовим SQL-программу ..\VCREATE.SQL и выполним ее. Протокол работы этой программы:
SET NAMES WIN1251;
CONNECT 'SKLAD\Ib_sklad.gdb'
USER 'SYSDBA' PASSWORD 'masterkey';
DROP VIEW RasxodDoc;
DROP VIEW RasxodNoKz;
CREATE VIEW RasxodDoc
(KOD_RASH, DATA_RASH, KOLVO, STOIM,
KOLVO_ZENA,
POKUP, GOROD, ADRES, TEL,
TOVAR, ED_IZM, ZENA, COUNT_TOV)
AS SELECT
RASXOD.KOD_RASH, RASXOD.DATA_RASH, RASXOD.KOLVO, RASXOD.STOIM,
RASXOD.KOLVO*TOVARY.ZENA,
POKUPATELI.POKUP, POKUPATELI.GOROD, POKUPATELI.ADRES, POKUPATELI.TEL,
TOVARY.TOVAR, TOVARY.ED_IZM, TOVARY.ZENA, TOVARY.COUNT_TOV
FROM RASXOD, POKUPATELI, TOVARY
WHERE ((RASXOD.KOD_POKUP=POKUPATELI.KOD_POKUP) AND
(RASXOD.KOD_TOVAR=TOVARY.KOD_TOVAR) AND
(POKUPATELI.GOROD<>'Казань'));
SELECT * FROM RasxodDoc ORDER BY KOD_RASH;
См. результат RDOC.DOC
INSERT INTO RasxodDoc (KOD_RASH, DATA_RASH, KOLVO, STOIM)
VALUES (20,'23.05.02', 110,1100);
Statement failed, SQLCODE = -150
cannot update read-only view RASXODDOC
INSERT INTO Rasxod (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (20,'23.05.02', 110,1100,4,5);
SELECT * FROM RasxodDoc ORDER BY KOD_RASH;
SELECT * FROM Rasxod ORDER BY KOD_RASH;
KOD_RASH DATA_RASH KOLVO STOIM KOD_TOVAR KOD_POKUP
2 12-APR-1998 10 120 1 6
5 12-JUL-2000 12 120 4 5
6 13-SEP-2000 5 25 2 2
7 15-SEP-2000 1 10 6 6
8 16-JUL-2000 7 70 6 1
9 23-MAY-2000 11 110 4 1
11 12-APR-2003 10 50 2 6
20 23-MAY-2002 110 1100 4 5
CREATE VIEW RasxodNoKz
AS SELECT * FROM RASXOD WHERE
('Казань'<>(SELECT GOROD FROM POKUPATELI
WHERE (RASXOD.KOD_POKUP=POKUPATELI.KOD_POKUP)));
SELECT * FROM RasxodNoKz ORDER BY KOD_RASH;
KOD_RASH DATA_RASH KOLVO STOIM KOD_TOVAR KOD_POKUP
2 12-APR-1998 10 120 1 6
5 12-JUL-2000 12 120 4 5
6 13-SEP-2000 5 25 2 2
7 15-SEP-2000 1 10 6 6
11 12-APR-2003 10 50 2 6
20 23-MAY-2002 110 1100 4 5
INSERT INTO RasxodNoKz (KOD_RASH, DATA_RASH, KOLVO, STOIM, KOD_TOVAR, KOD_POKUP)
VALUES (21,'23.05.02', 120,1200,4,5);
SELECT * FROM RasxodNoKz ORDER BY KOD_RASH;
KOD_RASH DATA_RASH KOLVO STOIM KOD_TOVAR KOD_POKUP
2 12-APR-1998 10 120 1 6
5 12-JUL-2000 12 120 4 5
6 13-SEP-2000 5 25 2 2
7 15-SEP-2000 1 10 6 6
11 12-APR-2003 10 50 2 6
20 23-MAY-2002 110 1100 4 5
21 23-MAY-2002 120 1200 4 5
SELECT * FROM Rasxod ORDER BY KOD_RASH;
KOD_RASH DATA_RASH KOLVO STOIM KOD_TOVAR KOD_POKUP
2 12-APR-1998 10 120 1 6
5 12-JUL-2000 12 120 4 5
6 13-SEP-2000 5 25 2 2
7 15-SEP-2000 1 10 6 6
8 16-JUL-2000 7 70 6 1
9 23-MAY-2000 11 110 4 1
11 12-APR-2003 10 50 2 6
20 23-MAY-2002 110 1100 4 5
21 23-MAY-2002 120 1200 4 5
EXIT;
Представление RasxodDoc для каждого документа о покупке содержит полную пользовательскую информацию - включает реквизиты покупателя и товара вместо их кодов. Отметим, что реквизит «стоимость покупки» вычислим и определен в этом представлении (KOLVO_ZENA)… использование хранимого значения этого реквизита в поле STOIM таблицы RASXOD требует обоснования…
К сожалению, так определенное представление не является модифицируемым, сообщение об ошибке к первому INSERT это иллюстрирует. Второй оператор INSERT иллюстрирует специфику представлений - изменение внесено в таблицу Rasxod, но оно отобразилось и в RasxodDoc.
Представление RasxodNoKz имеет такие же поля, как и таблица Rasxod, но оно включает строки только о покупках не Казанских покупателей. RasxodNoKz - модифицируемое представление, это иллюстрирует третий INSERT, который добавляет строку в RasxodNoKz. Эта строка появляется и в таблице Rasxod, что опять же иллюстрирует специфику представлений.
3. Администрирование базы данных. BDE. Создание псевдонима
Мощность и гибкость Delphi при работе с базами данных основана на низкоуровневом ядре - процессоре баз данных Borland Database Engine (BDE). BDE представляет собой совокупность динамических библиотек и драйверов, позволяющих осуществлять доступ к данным как с использованием традиционного record-ориентированного (навигационного) подхода (обрабатывается отдельно каждая запись таблицы), так и с использованием set-ориентированного подхода, используемого в SQL-серверах баз данных (одновременно обрабатывается группа записей). Приложение через BDE передает запрос к базе данных и получает требуемые данные.
Кроме BDE, Delphi позволяет осуществлять доступ к базам данных, используя технологию (и, соответственно, драйверы) Open DataBase Connectivity (ODBC) фирмы Microsoft. Но, как показывает практика, производительность систем с использованием BDE гораздо выше, чем оных при использовании ODBC. ODBC драйвера работают через специальный «ODBC socket», который позволяет встраивать их в BDE.
Все инструментальные средства баз данных Borland - Paradox, dBase, Database Desktop - используют BDE. Все особенности, имеющиеся в Paradox или dBase, «наследуются» BDE, и поэтому этими же особенностями обладает и Delphi.
Таблицы сохраняются в базе данных. Некоторые СУБД сохраняют базу данных в виде нескольких отдельных файлов, представляющих собой таблицы (в основном, все локальные СУБД), в то время как другие состоят из одного файла, который содержит в себе все таблицы и индексы (InterBase). InterBase сохраняет все таблицы в одном файле, имеющем расширение.GDB, поэтому этот файл и есть база данных InterBase.
Удобно не указывать путь доступа к таблицам базы данных, а использовать для этого некий заменитель - псевдоним, называемый алиасом. Он сохраняется в отдельном конфигурационном файле и позволяет исключить из программы прямое указание пути доступа к базе данных. Такой подход дает возможность располагать данные в любом месте, не перекомпилируя при этом программу. Кроме пути доступа, при алиасе указываются тип базы данных, языковый драйвер и много другой управляющей информации. Поэтому использование алиасов позволяет легко переходить от локальных баз данных к SQL-серверным базам (естественно, при выполнении требований разделения приложения на клиентскую и серверную части).
Для создания алиаса необходимо запустить утилиту конфигурации BDE (BDE administrator, программу BDEADMIN.EXE), находящуюся в директории, в котором располагаются динамические библиотеки BDE. После запуска необходимо выбрать режим создания нового алиаса (пункт меню Object > New), выбрать в появившемся списке драйверов драйвер IntrBase и настроить пункты появившейся формы:
LangDriver - Pdox Ansi Cyrillic (обработка русской кириллицы в Ansi-кодировке)
Server Name - C:\UCHBASE\SKLAD\Ib_sklad.gdb (полный путь к базе данных)
User Name - SYSDBA (системное имя пользователя)
В правой части экрана необходимо заменить стандартный алиас IntrBase на свой (в примере использован алиас Al_Sklad).
база данные товар покупатель
4. Разработка клиентского места
В данной методической разработке рассмотрены две реализации клиентского приложения на Object_Pascal и C++. Причем для сопоставимости в качестве среды разработки выбраны DELPHI6 BORLAND C++BUILDER6. Такой выбор позволил продемонстрировать реализацию клиентского приложения с использованием одной и той же объектной библиотеки, а отличия в коде связаны только с особенностью используемых языков программирования. Коды используемых процедур приводятся в виде таблицы, левая колонка которой связана с языком Object_Pascal, а правая - с C++. При выполнении курсового проекта студент может выбрать любую реализацию.
Основная экранная форма
Имеются несколько основных компонент (классов), которые используются для доступа к БД. Эти классы делятся на три группы:
невизуальные: TDataBase, TTable, TQuery, TField
визуальные: TDBGrid, TDBEdit
связующие: TDataSource
Первая группа включает невизуальные классы, которые используются для управления базами данных, таблицами и запросами. Эта группа сосредотачивается вокруг компонент типа TDataBase, TTable, TQuery и TField. В Палитре Компонент они расположены на странице BDE.
Вторая важная группа классов - визуальные, которые показывают данные пользователю, и позволяют ему просматривать и модифицировать их. Эта группа классов включает компоненты типа TDBGrid, TDBEdit, TDBImage и TDBComboBox. В Палитре Компонент они расположены на странице Data Controls.
Третий тип, используется для того, чтобы связать предыдущие два типа объектов. К этому типу относится невизуальный компонент TDataSource (на странице Data Access).
Рассмотрим последовательность действий построения клиентской части программы ..\PRG0\SKLAD.DPR.
Object_Pascal |
Borland_C++ |
|
1. Запустить Delphi. В результате загрузится новый проект с формой. |
1. Запустить С++Builder6. В результате загрузится новый проект с формой. |
|
2. Выбрать набор инструментов Data Access. Перенести на форму копию объекта типа TDataBase. Настроить параметры объекта DataBase как показано ниже |
2. Выбрать набор инструментов Data Access. Перенести на форму копию объекта типа TDataBase. Настроить параметры объекта DataBase как показано ниже |
Параметр Login prompt должен иметь значение false. В противном случае, при любом обращении к базе данных система будет запрашивать у пользователя пароль доступа к БД. Поле отметки Keep Inactive Connection в отмеченном состоянии означает, что соединение с БД будет сохраняться даже, если ни один набор данных этой базы данных не будет открыт. В окне Parameter overrides можно переустановить параметры псевдонима БД и драйвера.
Элемент типа TDataBase создается для каждого факта соединения с отдельной базой данных. Случаи явного использования в приложении компонента TDataBase чаще всего связаны с работой в архитектуре клиент-сервер. Явно определенный в программе компонент TDataBase облегчает управление БД, создавая постоянные соединения с ней, настраивая сеанс соединения с базой данных, управляя транзакциями, создавая локальные псевдонимы BDE. Каждый набор данных, работающий с таблицами одной и той же БД, может иметь с этой базой отдельное соединение. Однако это нерационально, поскольку каждое соединение съедает системные ресурсы. Для минимизации их использования рекомендуется создавать единственное соединение с базой данных при помощи компонента TDataBase, а все наборы данных, реализующие действия над БД, соединять с этим компонентом. Соединение активизируется установкой свойства Connected в значение true. Свойство DataBaseName определяет локальный псевдоним БД, который может использоваться при доступе к БД вместо псевдонима BDE.
3. Доступ к конкретной таблице БД регулируется компонентом TTable из набора Data Access. Для организации доступа к таблице «Товары» необходимо переместить копию компонента TTable на экранную форму и настроить в инспекторе объектов свойства DataBaseName (установить алиас UchSklad), свойство TableName (установить TOVARY). Кроме того, установим имя Name объекта как TovaryTable
Доступ к таблице регулируется установкой значения свойства Active в true. В программном коде открытие (закрытие) таблицы осуществляется также с помощью метода TovaryTable. Open (TovaryTable. Close).
TTable представляет собой пример невизуального компонента и становится невидимым при запуске программы. Для визуализации данных таблицы и интерактивной работы с ними служит компонент TDBGrid в группе Data Controls. Связь между визуальными и невизуальными компонентами осуществляется компонентом TdataSource. Этот класс используется в качестве проводника между TTable или TQuery и компонентами, визуализирующими данные, типа TDBGrid, TDBEdit и TDBComboBox (data-aware components). В большинстве случаев, все, что нужно сделать с DataSource - это указать в свойстве DataSet соответствующий TTable или TQuery. Затем, у data-aware компонента в свойстве DataSource указывается TDataSource, который используется в настоящее время. Любая таблица может быть открыта на этапе проектирования. При этом визуальные компоненты, связанные с таблицей, отображают текущее состояние записей соответствующего набора данных, но перемещение и редактирование записей невозможны. Исключение составляет возможность перемещения текущего указателя с помощью полосы прокрутки для визуальной компоненты TDBGrid.
TDataSource также имеет свойство Enabled, и оно может быть полезно всякий раз, когда Вы хотите временно отсоединить, например, DBGrid от таблицы или запроса. Это требуется, например, если нужно программно пройти через все записи в таблице. Ведь, если таблица связана с визуальными компонентами (DBGrid, DBEdit и т.п.), то каждый раз, когда Вы вызываете метод TTable. Next, визуальные компоненты будут перерисовываться. Даже если само сканирование в таблице двух или трех тысяч записей не займет много времени, то может потребоваться значительно больше времени, чтобы столько же раз перерисовать визуальные компоненты. В случаях подобных этому, лучше всего установить поле DataSource. Enabled в False. Это позволит просканировать записи без перерисовки визуальных компонент. Такая операция может увеличить скорость в некоторых случаях в десятки и сотни раз.
Свойство TDataSource. AutoEdit указывает, переходит ли DataSet автоматически в режим редактирования при вводе текста в data-aware объекте.
Перенесем компонент TDataSource на форму и установим свойство DataSet равным TovaryTable.
4. Перенесем компонент TDBGrid на форму. Установим значение свойства DataSource равным DataSource1. Добавим на форму компонент TDBNavigator, свойство DataSource которого установим равным DataSource1. Прежде чем запустить программу добавим на форму компонент TStoredProc, свойство DatabaseName которого установим равным UchSklad, а имя процедуры StoredProcName GET_KOD_TOVAR (Напомним, что эту процедуру мы создали ранее на сервере).
Далее найдем для объекта TovaryTable событие AfterInsert и определим обработчик этого события в виде процедуры
Object_Pascal |
Borland_C++ |
|
procedure Form1. TovaryTableAfterInsert (DataSet: TDataSet);beginStoredProc1. ExecProc;TovaryTable. FieldByName ('Kod_Tovar').Value:=StoredProc1. ParamByName('NR').Value;end; |
Void __fastcall TForm1: TovaryTableAfterInsert (TDataSet *DataSet){StoredProc1->ExecProc();TovaryTable-> FieldByName («Kod_Tovar»)->Value= StoredProc1->ParamByName («NR»)->Value;} |
Оператор StoredProc1. ExecProc (В C++ функция StoredProc1->ExecProc();) запускает процедуру с именем GET_KOD_TOVAR на сервере. Полученный результат присваивается полю Kod_Tovar. При помощи этой процедуры можно автоматически увеличивать значение поля Kod_Tovar на 1.
Кнопки объекта DBNavigator1 имеют слева направо следующие значения:
Первая запись
Предыдущая
Следующая
Последняя запись
Вставка записи
Удаление записи
Редактирование записи
Подтверждение редактирования
Отказ от изменений
Обновление данных
Изменив соответствующим образом список Hints у навигатора, и установив флажок на форме ShowHint в true, можно получить эти записи в качестве подсказок на экране при фокусировке мыши на соответствующей кнопке.
Аналогичным образом можно получить доступ к записям таблиц «Покупатели» и «Расход товара».
При работе с форматами данных различных регионов бывает необходимо настроить форматы дат, времени, различные разделители. Настройку можно сделать:
на уровне операционной системы (через настройку свойств «языки и стандарты» панели управления)
на уровне BDE (настройка параметров драйверов)
на уровне клиентской части программы
Ниже приводится пример такой настройки на уровне клиентской части программы. Для этого необходимо построить обработчик события OnCreate формы в виде процедуры
Object_Pascal |
Borland_C++ |
|
procedure TForm1. FormCreate (Sender: TObject); begin DateSeparator:='.'; ShortDateFormat:='dd.mm.yyyy'; ShortTimeFormat:='hh:mm:ss'; end; |
void __fastcall TForm1: FormCreate (TObject *Sender) { DateSeparator='.'; ShortDateFormat= «dd.mm.yyyy»; ShortTimeFormat= «hh:mm:ss»;} |
Системная переменная (модуля SysUtils) DateSeparator описывает разделитель, переменные ShortDateFormat и ShortTimeFormat задают форматы дат и времени. Процедура отрабатывает при запуске программы при создании формы.
В качестве примера динамического перепрограммирования свойств объектов приведем пример обслуживания одним навигатором двух таблиц «Товары» и «Покупатели». Как уже упоминалось выше, в навигаторе свойство DataSource необходимо настроить на имя компонента TDataSource, связывающий навигатор с определенной таблицей. Изменяя динамически эту связь можно одним навигатором обслуживать различные таблицы.
Перенесем на форму копию компонента Tlabel и напишем обработчик события OnEnter для объекта DBGrid1.
Object_Pascal |
Borland_C++ |
|
procedure TForm1.DBGrid1Enter (Sender: TObject); begin DBNavigator1. DataSource:= DataSource1; DBNavigator1. Enabled:=True; Label1. Caption:='Товары'; end; |
void __fastcall TForm1:DBGrid1Enter (TObject *Sender) { DBNavigator1-> DataSource=DataSource1; DBNavigator1->Enabled=True; Label1->Caption= «Товары»;} |
Аналогичную процедуру
Object_Pascal |
Borland_C++ |
|
procedure TForm1.DBGrid2Enter (Sender: TObject); begin DBNavigator1. DataSource:= DataSource2; DBNavigator1. Enabled:=True; Label1. Caption:='Покупатели'; end; |
void __fastcall TForm1:DBGrid2Enter (TObject *Sender) { DBNavigator1-> DataSource=DataSource2; DBNavigator1->Enabled=True; Label1->Caption= «Покупатели»;} |
будем использовать как обработчик события OnEnter для объекта DBGrid2.
Запустив программу можно убедиться, что любое переключение между объектами Grid для таблиц «Товары» и «Покупатели» изменяет состояние метки Label1, которое показывает, какой таблицей в настоящий момент управляет навигатор.
Для таблицы «Расход товара» построим собственный навигатор, используя методы объекта TTable.
В частности, если на форме имеется объект Table1, то методы Table1. First, Table1. Last, Table1. Next, Table1. Prior - осуществляют соответственно переход к первой, последней, следующей и предыдущей записи.
Добавление новой записи осуществляется с использованием метода Table1. Add или Table1. Insert. Отличие метода Table1. Add от Table1. Insert состоит в том, что в первом случае запись добавляется в конец таблицы, а во втором - запись вставляется непосредственно перед записью, на который указывает курсор. Метод Table1. Delete удаляет текущую запись.
Метод Table1. Edit переводит таблицу в режим редактирования. Методы Table1. Post и Table1. Cancel означают соответственно подтверждение или отказ от сделанных изменений. Метод Table1. Refresh обновляет содержимое таблицы на форме. Необходимо помнить, что всякий раз, когда происходит смещение указателя с текущей записи, в таблице автоматически будут сохранены введенные данные. Это означает, что вызовы First, Next, Prior и Last всегда выполняют Post, если Вы находились в режиме редактирования. Если Вы работаете с данными на сервере и транзакциями, тогда правила, приведенные здесь, не применяются. Тем не менее, даже если Вы не работаете с транзакциями, Вы можете все же отменить результаты вашего редактирования в любое время, до тех пор, пока не вызвали напрямую или косвенно метод Post. Например, если Вы перевели таблицу в режим редактирования, и изменили данные в одном или более полей текущей записи, Вы можете всегда вернуть текущую запись в исходное состояние вызовом метода Cancel.
Наборы данных могут находиться в определенных состояниях. Состояние набора определяется свойством State. Это свойство доступно только для чтения и используется при выполнении операций над записями таблицы (некоторые операции над набором разрешены только в определенных состояниях). Для перевода набора данных в требуемое состояние используются специальные методы.
Перечислим основные состояния набора данных:
dsInactive - набор данных закрыт;
dsBrowse - набор данных находится в состоянии просмотра. Переход в этот режим происходит из режимов dsEdit и dsInsert при вызове одного из методов Post или Cancel.
dsEdit - набор данных находится в состоянии редактирования. Переход в этот режим происходит из режимов dsBrowse при вызове метода Edit.
dsInsert - набор данных находится в состоянии добавления новой записи. Переход в этот режим происходит из режимов dsBrowse при вызове одного из методов Insert, InsertRecord, Append или AppendRecord.
dsSetKey - режим поиска записей, удовлетворяющих некоторому условию. Переход в этот режим происходит из режимов dsBrowse при вызове одного из методов SetKey, FindKey, GotoNearest или FindNearest. Возможен только для компоненты типа TTable, для компоненты TQuery отбор записей осуществляется средствами языка SQL.
dsOpening - набор данных находится в открытом состоянии.
Построим на форме кнопки «Следующая» (Next) и «Вставить» (Add), выбирая компонент Button из палитры Standart. В обработчик события OnClick первой кнопки вставим процедуру
Object_Pascal |
Borland_C++ |
|
procedure TForm1. NextClick (Sender: TObject); begin IF NOT RasxodTable.EOF THENRasxodTable. NextELSE Next. Enabled:=False;end; |
void __fastcall TForm1: NextClick (TObject *Sender)if (! RasxodTable->Eof)RasxodTable->Next();else Next->Enabled=False;} |
а в соответствующий обработчик второй кнопки процедуру
Object_Pascal |
Borland_C++ |
|
procedure TForm1. AddClick (Sender: TObject);beginRasxodTable. Insert;end; |
void __fastcall TForm1: AddClick (TObject *Sender){RasxodTable->Insert();} |
Задача: Построить код для своего навигатора таблицы «Расход товара», смоделировав работу навигатора из визуальной библиотеки компонент.
Выше уже отмечалось, что таблицы «Товары» и «Расход товара» связаны по формулам:
Стоимость купленного товара:=Количество купленного товара * цена единицы товара,
Количество товара на складе:= Количество товара на складе - Количество купленного товара.
При этом заметим, «Количество купленного товара» и «цена единицы товара» («Количество товара на складе») лежат в разных таблицах. Решением второй задачи мы уже занимались.
Подобные документы
Разработка базы данных с информацией о сотрудниках, товарах, со справочником типов товаров средствами системы управления базами данных MySQL с помощью SQL-запросов. Разработка инфологической модели предметной области. Структура таблиц, полей базы данных.
контрольная работа [648,7 K], добавлен 13.04.2012Проектирование базы данных "Автосалон" с использованием Microsoft Access. Создание таблиц с информацией об автомобилях, их стоимости, стране-производителе, покупателях. Построение информационной схемы базы, форм для занесения данных в таблицы и отчета.
контрольная работа [5,2 M], добавлен 28.06.2011Авторизация с каталогами проектирования базы данных магазина. Задачи базы данных: учет всех товаров, поиск и выдача данных о клиентах, адрес, телефоны, цена и наличие товара. Этапы проектирования базы данных. Схема данных, создание запросов и их формы.
реферат [1,6 M], добавлен 22.10.2009Создание базы данных. Поиск, изменение и удаление записей. Обработка и обмен данными. Проектирование базы данных. Определение формул для вычисляемой части базы. Редактирование полей и записей. Формы представления информации, содержащейся в базе данных.
курсовая работа [67,0 K], добавлен 23.02.2009Современные базы данных – многофункциональные программные системы, работающие в открытой распределенной среде изучении администрирования базы данных. Способы организации внешней памяти баз данных. Системы управления базами данных для хранения информации.
курсовая работа [185,6 K], добавлен 07.12.2010Основные виды баз данных. Система управления базами данных. Анализ деятельности и информации, обрабатываемой в поликлинике. Состав таблиц в базе данных и их взаимосвязи. Методика наполнения базы данных информацией. Алгоритм создания базы данных.
курсовая работа [3,1 M], добавлен 17.12.2014Сущность базы данных. Процесс построения концептуальной модели. Построение реляционной модели, создание ключевого поля. Процесс нормализации. Проектирование базы данных в ACCESS. Порядок создание базы данных. Создание SQL запросов и работа в базе данных.
курсовая работа [185,6 K], добавлен 08.11.2008Цель создания базы данных магазина. Понятие и сущность инфологического моделирования, его применение. Особенности разработки базы данных, создание таблиц, схемы данных, запросов, визуальных и печатных форм. Описание процесса работы с базами данных.
курсовая работа [1,9 M], добавлен 15.11.2013Создание программ, позволяющих создавать базы данных. Создание таблицы базы данных. Создание схемы данных. Создание форм, отчетов, запросов. Увеличение объема и структурной сложности хранимых данных. Характеристика системы управления базой данных Access.
курсовая работа [2,1 M], добавлен 17.06.2013Создание таблиц базы данных с помощью MS Access "Страны Азии". Форма базы данных и запросы к выборкам данных. Модификация структуры таблиц, создания связей между главными таблицами, редактирование данных и проектирование форм для реальной базы данных.
контрольная работа [723,9 K], добавлен 25.11.2012