л.р.5 - Разработка баз данных средствами SQL-сервера Interbase. Команды языка SQL для описания данных.
========= Отчет лаб5 ===============
В этой работе нет Делфи-проекта. Создается база данных Interbase.
Описан процесс создания базы данных, доменов, таблиц, генераторов,
триггеров, хранимых процедур, заполнения таблиц.
( БД из лаб2-4 создана другими средствами). Делфи-проект, работающий
с этой БД рассмотрен в лаб6.
-----------------------------
Задание:
1. Выполнить анализ схемы данных разработанной ранее БД для исключения
возможности возникновения аномалий модификации данных.
******* это не выполнялось
2. С целью доказательства нахождения разработанной схемы в 3НФ
(или НФБК), для каждого отношения (таблицы) определить функциональные
зависимости. При выявлении аномалий модели данных выполнить ее
нормализацию, следуя алгоритму нормализации.
******* это не выполнялось
3. Создать БД на сервере InterBase и зарегистрировать ее с использованием
приложения IBConsole.
\Program Files\Borland\InterBase\bin\IBConsole.exe
- Зарегистрирован админ:
Регистрация сервера осуществляется в диалоговом окне, которое
открывается командой Server – Register, в котором необходимо указать имя
администратора БД (User Name) - SYSDBA и его пароль (Password) – masterkey.
При регистрации локального сервера в открывшемся окне должна быть включена
радиокнопка Local Server.
( Не описано в методичке:
Как открыть сервер: можно дв щелчком по ярлыку "Local Server",
ввести пароль. Красный крест заменится зеленой птичкой. Ингда открывается
долго)
- Регистрируем фирменную демо-БД: Меню\DataBase\Register
Здесь в окне DataBase настроить БД на адрес
Program Files\Common Files\Borland Shared\Data\EMPLOYEE.GDB
- как сказано в методичке.
При регистрации БД
можно ввести Login Information.
Ввел (и для своей БД то же)
UserName: WINNI
Password: krolik
Role:
Default Character Set: WIN1251
--- Однако эти UserName, Password не используются. Нужно вводить
SYSDBA masterkey -------------
После этого в окне появляется эта БД и можно смотреть ее детали:
таблицы, индексы и т д.
- Полезно поизучать эту демо-бд (см scr1.gif-scr3.gif)
- Все это работает и ДО регистрации сервера InterBase с использованием
приложения SQLExplorer. SQLExplorer удобен для просмотра структуры БД,
ввода SQL запросов (см scr5,6,7)
4. Создать алиас БД сервера InterBase с использованием приложения
SQLExplorer.
- открываю SQLExplorer (из группы Делфи или \Program Files\Borland\Delphi7\Bin\dbexplor.exe)
- Создаю алиас БД сервера InterBase:
- Меню | Object | New
- в окошке New DataBase alias выбираю INTRBASE, щелкаю ОК
- в правом окошке, закладка Definition устанавливаю Server Name
т е путь к БД:
\Program Files\Borland\InterBase\examples\Database\EMPLOYEE.GDB
(например. Там есть еще одна БД) или
\Program Files\Common Files\Borland Shared\Data\EMPLOYEE.GDB
Можно тут же установить
LANGDRIVER = Pdox ANSI Cirillic
USER NAME = SYSDBA
(см scr4.gif)
- Сделать правый щелчок на значке создаваемого алиаса INTRBASE1
и выбрать Apply (применть), щелк ОК.
(перед этим можно INTRBASE1 переименовать во что угодно)
- после этого созданный алиас (псевдоним) будет появляться в окошках
доступных алиасов в тех программах, где есть такое окошко
(список создается компонентом TSession, например:
ses1.GetAliasNames(cbAliases.Items); )
Однако в этих лаб. работах этот алас не используется, т е
как бы непонятно, зачем его создавать.
5. Познакомиться с возможностями приложений IBConsole и SQLExplorer при
создании и выполнении команд SQL в интерактивном режиме.
- Открываю IBConsole
- дв щелчок на Local Server, ввожу пароль. Выделяю EMPLOYEE.GDB
- DataBase\Connect (или дв щелч на значке этой БД)
- Для работы с SQL: Меню\Tools\Interactive SQL
---------------------
Примеры SQL:
- в списке таблиц вижу EMPLOYEE
для ее просмотра ввожу SQL: SELECT * FROM EMPLOYEE
(в верхнее окно Interactive SQL). Щелкаю кнопку Execute Query
(молния со знаком ?)
В нижнем окне появляется таблица-результат.
- усложняю запрос сортировкой:
SELECT * FROM EMPLOYEE
ORDER BY FIRST_NAME
** выполнено нормально
- еще:
SELECT * FROM EMPLOYEE
WHERE JOB_COUNTRY = 'Italy' OR
JOB_COUNTRY = 'USA'
ORDER BY FIRST_NAME
** выполнено нормально
т е выполняются любые обычные SQL-запросы.
--------------------------
6. С использованием команд SQL определения данных создать следующие
объекты БД: ....
Создание новой БД обеспечивается командой Database – Create Database.
После ее выполнения открывается диалоговое окно, в котором в панели File(s)
надо записать имя файла создаваемой БД с полным путем доступа к нему.
- создаю пустую папку, например:
E:\XRAN_RW_MyProg\Apteka\IB_kassa6_2
- Открываю IBConsole, ввожу пароль masterkey
- IBConsole | Database | Create Database
- вписываю E:\XRAN_RW_MyProg\Apteka\IB_kassa6_2\kas6_2.gdb
(т е создаю новую, другую БД). Size = 250
Alias= IB_kassa6_2.
- получается пустая БД (однако файл KAS6_2.GDB имеет размер 590 Кб)
- теперь в верхнее окно Interactive SQL можно вводить запросы
по созданию объектов: доменов, таблиц и т д. После вписания запроса
Щелкаю кнопку Execute Query (молния со знаком ?)
Интересно, что можно в окно поместить несколько запросов (в конце
запроса ;) и выполнить сразу все.
• домены для тех типов данных и ограничений, которые повторяются при
определении нескольких полей (определяются на основании анализа типов
полей всех таблиц БД).
- вначале создаются домены (хотя можно без них)
тексты запросов можно видеть (и копировать) в БД kas6.gdb и
EMPLOYEE.GDB. (правый щелчок по домену, выбрать extract)
Получим, например:
/* Domain definitions */
CREATE DOMAIN "CHAR10" AS VARCHAR(10) CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN "CHAR30" AS VARCHAR(30) CHARACTER SET WIN1251;
Введем сразу эти 2 заапроса, как было описано выше, в БД
kas6_2.gdb. (Выделим ее в окошке, Tools | Interactive SQL)
видим (scr8.gif)
Вводим остальные домены
/* Domain definitions */
CREATE DOMAIN "CHAR100" AS VARCHAR(100) CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN "CHAR12" AS VARCHAR(12) CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN "CHAR20" AS VARCHAR(20) CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN "CHAR50" AS VARCHAR(50) CHARACTER SET WIN1251;
/* Domain definitions */
CREATE DOMAIN "COUNT1" AS SMALLINT
CHECK (VALUE >= 0);
/* Domain definitions */
CREATE DOMAIN "ID1" AS SMALLINT;
/* Domain definitions */
CREATE DOMAIN "MONEY" AS NUMERIC(8, 2)
DEFAULT 0
CHECK (VALUE > 0);
----------------------------
• таблицы (с обязательным определением первичных и внешних ключей,
ссылочной целостности связанных таблиц, с вычисляемыми полями и
ограничениями на ввод допустимых значений в отдельные поля);
- таблицы создаются запросами вида:
CREATE TABLE AP_USERS
(
ID_USERS ID1 NOT NULL,
NAME CHAR100 NOT NULL,
EMAIL CHAR30 NOT NULL UNIQUE,
PASS CHAR20 NOT NULL,
CONTACTFIO CHAR30 NOT NULL,
ID_COUNTRY ID1 NOT NULL,
PINDEX CHAR10 NOT NULL,
CITY CHAR20 NOT NULL,
PADDRESS CHAR50 NOT NULL,
PHONE CHAR12,
FAX CHAR12,
ETC CHAR50,
PRIMARY KEY (ID_USERS)
);
ALTER TABLE AP_USERS ADD FOREIGN KEY (ID_COUNTRY) REFERENCES COUNTRIES
(ID_COUNTRY);
Однако,
ALTER TABLE AP_USERS ADD FOREIGN KEY (ID_COUNTRY) REFERENCES COUNTRIES
(ID_COUNTRY); не вводится, т к нет еще табл COUNTRIES, т е лучше начать
с COUNTRIES:
CREATE TABLE "COUNTRIES"
(
"ID_COUNTRY" "ID1" NOT NULL,
"COUNTRY" "CHAR20" NOT NULL,
CONSTRAINT "CONS2" UNIQUE ("COUNTRY"),
PRIMARY KEY ("ID_COUNTRY")
);
а теперь повторно ввести
ALTER TABLE AP_USERS ADD FOREIGN KEY (ID_COUNTRY) REFERENCES COUNTRIES
(ID_COUNTRY); - нормально. Т е начинать лучше с независимых таблиц.
--------
CREATE TABLE KATEGORII
(
ID_KATEGOR ID1 NOT NULL,
KATEGOR CHAR20 NOT NULL,
PRIMARY KEY (ID_KATEGOR)
);
/* Table: LEK_LIST, Owner: SYSDBA (Winni - krolik) */
CREATE TABLE LEK_LIST
(
LEK_ID ID1 NOT NULL,
ID_KATEGOR ID1 NOT NULL,
NAZVZAN1 CHAR30,
NAZVZAN2 CHAR30,
NAZVZAN3 CHAR50,
CENA MONEY NOT NULL,
PRIMARY KEY (LEK_ID)
);
ALTER TABLE LEK_LIST ADD FOREIGN KEY (ID_KATEGOR) REFERENCES KATEGORII
(ID_KATEGOR);
- эти 2 табл созданы за один щелчок по Execute Query(молния со знаком ?)
-------------
/* Table: SKLAD, Owner: SYSDBA (Winni - krolik) */
CREATE TABLE SKLAD
(
LEK_ID ID1 NOT NULL UNIQUE,
OSTATOK COUNT1,
STELLAJ CHAR20
);
ALTER TABLE SKLAD ADD FOREIGN KEY (LEK_ID) REFERENCES LEK_LIST (LEK_ID);
-----------------
• генераторы для ключевых полей таблиц, имеющих автоинкрементный
тип данных;
- CREATE GENERATOR "AP_USERS_ID";
CREATE GENERATOR "COUNTRIES_ID";
CREATE GENERATOR "KATEGORII_ID";
вводится в верхнее окно Interactive SQL.
Генераторы (объекты, похожие на переменные в программировании)
созданы.
• триггеры для работы генераторов;
-------
SET TERM ^ ;
/* Triggers only will work for SQL triggers */
CREATE TRIGGER "SET_ID_CNTR" FOR "COUNTRIES"
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
new.ID_COUNTRY = gen_id(COUNTRIES_ID, 1);
END
^
SET TERM ;^
--------------
SET TERM ^ ;
CREATE TRIGGER "SET_ID_KATEGOR" FOR "KATEGORII"
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
new.ID_KATEGOR = gen_id(KATEGORII_ID, 1);
END
^
SET TERM ;^
--------------
Эти запросы вводятся в то же окошко.
Тексты для образца и копирования находятся:
- правый щелчок по БД (KAS6.gdb), выбрать View MetaData.
• просмотры:
---------
SQL-запросы на создание просмотров.
CREATE VIEW SPISOK1 AS
SELECT NAZVZAN1, OSTATOK, CENA
FROM LEK_LIST, SKLAD
WHERE SKLAD.LEK_ID = LEK_LIST.LEK_ID;
CREATE VIEW SPISOK2 AS
SELECT KATEGOR, NAZVZAN1, OSTATOK, CENA
FROM KATEGORII, LEK_LIST, SKLAD
WHERE (LEK_LIST.ID_KATEGOR = KATEGORII.ID_KATEGOR) AND
(SKLAD.LEK_ID = LEK_LIST.LEK_ID);
------- Использование просмотра ---------
SELECT * FROM SPISOK2
ORDER BY KATEGOR, CENA;
---------
Чтобы это работало в лаб6, нужно или
- заменить файл БД: KAS6.gdb (прилагается)
- в приложении лаб6 (Apteka6.exe) щелкнуть кнопку
Ввод запросов и выполнить запрос:
SELECT * FROM SPISOK2
ORDER BY KATEGOR, CENA;
------
или выполнить запросы CREATE на создание
в IBConsole.exe => изменится KAS6.gdb а потом
- в приложении лаб6 (Apteka6.exe) щелкнуть кнопку
Ввод запросов и выполнить запрос:
SELECT * FROM SPISOK2
ORDER BY KATEGOR, CENA;
(см scr9.gif)
---------
• индексы;
- индексы создавались в запросах на создание таблиц,
например:
CREATE TABLE "AP_USERS"
(
"ID_USERS" "ID1" NOT NULL,
......,
UNIQUE ("EMAIL"),
PRIMARY KEY ("ID_USERS")
);
-------------
CREATE TABLE "COUNTRIES"
( ....
CONSTRAINT "CONS2" UNIQUE ("COUNTRY"),
PRIMARY KEY ("ID_COUNTRY")
);
----------
• хранимые процедуры. Например: ;
SET TERM ^ ;
CREATE PROCEDURE "DELETE_LEKAR"
(
"LEKID" INTEGER
)
AS
BEGIN
DELETE FROM LEK_LIST
WHERE (LEK_ID = :LEKID);
END
^
SET TERM ; ^
----------
Автоматика разбивает это на 2 запроса: CREATE и ALTER
(см в БД)
--------
SET TERM ^ ;
CREATE PROCEDURE "INSERT_LEKAR"
(
"LEKID" INTEGER,
"IDKATEGOR" INTEGER,
"N1" VARCHAR(30) CHARACTER SET WIN1251,
"N2" VARCHAR(30) CHARACTER SET WIN1251,
"N3" VARCHAR(40) CHARACTER SET WIN1251,
"CENA" NUMERIC(8, 2)
)
AS
BEGIN
INSERT INTO LEK_LIST
VALUES (:LEKID, :IDKATEGOR, :N1, :N2, :N3, :CENA);
END
^
SET TERM ; ^
----
В начале и в конце меняется ограничитель запроса, так как ;
используется внутри текста запроса.
--------
SET TERM !!;
CREATE PROCEDURE UPDATE_LEKAR
(LEKID INTEGER, IDKATEGOR INTEGER, N1 VARCHAR(30), N2 VARCHAR(30),
N3 VARCHAR(40), CENA NUMERIC (8,2))
AS
BEGIN
UPDATE LEK_LIST
SET
LEK_ID = :LEKID,
ID_KATEGOR = :IDKATEGOR,
NAZVZAN1 = :N1,
NAZVZAN2 = :N2,
NAZVZAN3 = :N3,
CENA = :CENA
WHERE LEK_ID = :LEKID;
END !!
SET TERM ; !!
• триггеры для реализации правил бизнес – логики.
-----------------------------
====== Бизнес-правила для связи lek_list <---> kategorii =====
A)lek_list:
+Before_Insert - поле Id_kategor вводить выбором из списка категорий.
Или проверять, что вводимое значение Id_kategor
есть в табл kategorii
After_Insert ---
------------
Before_Delete --
After_Delete --
------------
+Before_Update - поле Id_kategor вводить выбором из списка категорий.
Или проверять, что вводимое значение Id_kategor есть в табл kategorii
After_Update --
==============
B)kategorii:
Before_Insert ---
After_Insert ---
------------
Before_Delete
Проверить: если есть связанные записи в lek_list, выдать сообщение
и не удалять или
предложить удалить все лекарства этой категории (каскадно).
After_Delete ---
------------
Before_Update
Проверить: если есть связанные записи в lek_list, запретить
редактирование ключа Id_kategor. Или проверить - есть ли
новое значение в табл kategorii
After_Update ---
------------- триггеры, реализующие эти бизнес-правила, см далее ----
------- Добавлены исключения для триггеров: ---------
CREATE EXCEPTION no_del_kat 'Нельзя удалять - есть лекарства этой категории';
CREATE EXCEPTION no_ins_lek 'Нельзя добавить - нет такой категории';
CREATE EXCEPTION no_upd_kat 'Нельзя изменить - есть лекарства этой категории';
CREATE EXCEPTION no_upd_lek 'Нельзя изменить - нет такой категории';
========= ТРИГГЕРЫ: ==========
SET TERM !! ;
CREATE TRIGGER BEFORE_DELETE_KAT FOR KATEGORII
ACTIVE BEFORE DELETE POSITION 0
AS
DECLARE VARIABLE lek_count INTEGER ;
BEGIN
SELECT count(lek_id) from LEK_LIST
WHERE LEK_LIST.ID_KATEGOR = KATEGORII.ID_KATEGOR
INTO :lek_count ;
IF (:lek_count > 0) THEN EXCEPTION no_del_kat ;
END !!
SET TERM ; !!
------- эта версия работает -------
================
SET TERM !! ;
CREATE TRIGGER BEFORE_INSERT_LEK FOR LEK_LIST
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE kat_count INTEGER;
BEGIN
SELECT count(ID_KATEGOR) from KATEGORII
WHERE KATEGORII.ID_KATEGOR = new.ID_KATEGOR
INTO :kat_count;
IF (:kat_count < 1) THEN EXCEPTION no_ins_lek;
END !!
SET TERM ; !!
------- это ^^ работает -------
=================================
SET TERM !! ;
CREATE TRIGGER BEFORE_UPDATE_KAT FOR KATEGORII
ACTIVE BEFORE UPDATE POSITION 0
AS
DECLARE VARIABLE lek_count INTEGER;
BEGIN
SELECT count(lek_id) from LEK_LIST
WHERE KATEGORII.ID_KATEGOR = LEK_LIST.ID_KATEGOR
INTO :lek_count;
IF (:lek_count > 0) THEN EXCEPTION no_upd_kat;
END !!
SET TERM ; !!
------- это ^^ не работает, т к ?? раньше срабатывает
ограничение FOREIGN KEY ("ID_KATEGOR") в табл LEK_LIST,
то есть это дублирование, поэтому убираю этот триггер.
----------------------------
SET TERM !! ;
CREATE TRIGGER BEFORE_UPDATE_LEK FOR LEK_LIST
ACTIVE BEFORE UPDATE POSITION 0
AS
DECLARE VARIABLE kat_count INTEGER;
BEGIN
SELECT count(ID_KATEGOR) from KATEGORII
WHERE KATEGORII.ID_KATEGOR = new.ID_KATEGOR
INTO :kat_count;
IF (:kat_count < 1) THEN EXCEPTION no_upd_lek;
END !!
SET TERM ; !!
- по русски: нельзя при редактировании менять поле ID_KATEGOR
устанавливая новое значение, которого нет в табл KATEGORII
Это работает, но в IBConsole раньше срабатывает ошибка
перекодировки. Если же новые значения писать латин, тогда видна
работа этого триггера. В лаб6 тоже раньше срабатывает блок
try ... except и выдает свой текст, после которого прога
выводит текст системный от EXCEPTION no_upd_lek, т е работает
нормально. Но это в версии лаб 6 от 31.12.08
Версия лаб6 от 31.12.08 показывает сообщения исключений
от InterBase, описанные вначале.
------------------------------
7. Познакомиться с синтаксисом операторов модификации объектов базы
данных с помощью справочной системы интерактивного SQL.+
- познакомился
-------
8. Получить навыки работы при работе с операторами SQL модификации
объектов БД. +
9. Отработать в режиме интерактивного SQL операторы манипулирования
данными. +
При выполнении лабораторной работы в качестве примера для создания
всех объектов БД использовать контрольный пример базы данных, входящий
в поставку InterBase, хранящийся в файле:
Program Files\Common Files\Borland Shared\Data\EMPLOYEE.GDB
---
10. Заполняю таблицы данными (снова SQL запросы):
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 4,'аллергия');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 5,'мать и дитя');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 6,'слабительные');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 7,'кандидоз');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 8,'лечебное питание');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 9,'антибиотики');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 10,'анальгетики');
INSERT INTO KATEGORII (ID_KATEGOR, KATEGOR)
VALUES ( 11,'тошнотворные (kas6)');
-----------
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 1,'Россия');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 2,'Республика Беларусь');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 3,'Франция');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 4,'Германия');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 5,'Казахстан');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 6,'Италия');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 7,'Швеция');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 8,'Норвегия');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 9,'Украина');
INSERT INTO COUNTRIES (ID_COUNTRY,COUNTRY)
VALUES ( 10,'Бельгия');
--------------- Не вводите это, прочтите дальше, чтобы избежать мороки
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 111,6,'ДУЛЬКОЛАКС','таблетки 5мг','BOEHRINGER INGELHEIM FRANCE',56);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 112,6,'ФОРТРАНС','порошок 64г','BEAUFOUR IPSEN INDUSTRIE',32);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 113,6,'ДЮФАЛАК','сироп 100мл','SOLVAY B.V.',113);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 114,4,'СУПРАСТИН','таблетки 25мг','EGIS PHARMACEUTICALS Ltd.',276);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 115,4,'АЛЛЕРТЕК','таблетки 10 мг','WARSAW PHARMACEUTICAL WORK POLSA',87);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 116,4,'АЛЛЕРТЕК','раствор-капли 1мл','NOVARTIS CONSUMER HEALTH S.A.',55);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 117,4,'ФЕНИСТИЛ','гель 1г','NOVARTIS CONSUMER HEALTH S.A.',107);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 118,4,'ФЕНИСТИЛ 24','капсулы 4 мг','NOVARTIS CONSUMER HEALTH S.A.',218);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 119,5,'СИМИЛАК С ЖЕЛЕЗОМ','смесь молочная сухая (на 1 л)','ALFA FOODS ARINCO',123);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 120,5,'СИМИЛАК ФОРМУЛА ПЛЮС 1','смесь молочная сухая (на 1 л)','ABBOT LABORATORIES S.A.',43);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 121,5,'СИМИЛАК ФОРМУЛА ПЛЮС 2','смесь молочная сухая (на 1 л)','ABBOT LABORATORIES S.A.',51);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 122,7,'АМФОТЕРИЦИН В','флаконы 10 мл 50 000 ед','СИНТЕЗ ОАО',231);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 123,7,'АМФОТЕРИЦИН В','мазь 1 г 30 000 ед','СИНТЕЗ ОАО',175);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 124,7,'НИСТАТИН','мазь 1 г 100 000 ед','НИЖФАРМ ОАО',45);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 125,7,'НИСТАТИН','таблетки 250 000 ед','БИОСИНТЕЗ ОАО',23);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 126,8,'ПРОТЕИН МОДУЛЬ','питательная смесь сухая 100 г','BERLIN-CHEMIE AG',76);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 127,8,'КАРНИТИН МОДУЛЬ','питательная смесь сухая 1 г','BERLAMIN MODULAR',27);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 128,8,'МСТ МОДУЛЬ','питательная смесь сух 1 пак','BERLAMIN MODULAR',231);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 129,9,'БИЦИЛЛИН-1','порошок 1 фл 1.2 млн ед','СИНТЕЗ ОАО',5.12);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 130,9,'БИЦИЛЛИН-3','порошок 1 фл 1.2 млн ед','СИНТЕЗ ОАО',7);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 131,9,'БИЦИЛЛИН-5','порошок 1 фл 1.2 млн ед','СИНТЕЗ ОАО',9);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 132,10,'М-ЭСЛОН','капсулы ретард 10 мг','GRUNENHAL GmbH',12);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 133,10,'М-ЭСЛОН','капсулы ретард 30 мг','GRUNENHAL GmbH',27);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 134,10,'М-ЭСЛОН','капсулы ретард 100 мг','GRUNENHAL GmbH',74);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 135,11,'РЕЛАДОРМ','таблетки','TARCHOMIN WORKS',48);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 136,11,'ЭСТАЗОЛАМ','таблетки 2 мг','TARCHOMIN WORKS',38);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 137,11,'СОМНОЛ','таблетки 7.5 мг','GRINDEX',61);
INSERT INTO LEK_LIST (LEK_ID, ID_KATEGOR, NAZVZAN1, NAZVZAN2, NAZVZAN3, CENA)
VALUES ( 144,6,'ДУЛЬКОЛАКС','таблетки 5мг','BOEHRINGER INGELHEIM FRANCE',56);
---------------
- это нарушает ограничение целостности. ID_KATEGOR>7 не существуют
в таб KATEGORII. Нужно триггер поставить после ввода таблицы
и начальное значение генератора установить. Т е:
- DROP TRIGGER SET_ID_KATEGOR;
- DELETE FROM LEK_LIST;
- DELETE FROM KATEGORII;
- Снова заполнить KATEGORII
- INSERT (тот же но только записи ID_KATEGOR < 8 - 4 записи).
Теперь ID_KATEGOR от 4 до 7, как и значение генератора=7.
- возвращаю триггер
- ввожу остальные записи (ID_KATEGOR > 7). Теперь значение генератора=11
и последнее значение ID_KATEGOR=11, так что дальше триггер будет
вырабатывать годные номера ID_KATEGOR=12,13,...
- Повторяем список INSERT (для LEK_LIST). На этот раз нормально.
- Вся эта морока потому, что не хочется менять старые номера ID_KATEGOR
(они связаны с табл LEK_LIST)
============== Структура БД ===========
----------- MetaData for KAS6.gdb ---------------
SET SQL DIALECT 3;
/* CREATE DATABASE 'E:\XRAN_RW_MyProg\Apteka\BD_IB_kassa6\KAS6.gdb'
PAGE_SIZE 4096
DEFAULT CHARACTER SET WIN1251 */
/* Domain definitions */
CREATE DOMAIN "CHAR10" AS VARCHAR(10) CHARACTER SET WIN1251;
CREATE DOMAIN "CHAR100" AS VARCHAR(100) CHARACTER SET WIN1251;
CREATE DOMAIN "CHAR12" AS VARCHAR(12) CHARACTER SET WIN1251;
CREATE DOMAIN "CHAR20" AS VARCHAR(20) CHARACTER SET WIN1251;
CREATE DOMAIN "CHAR30" AS VARCHAR(30) CHARACTER SET WIN1251;
CREATE DOMAIN "CHAR50" AS VARCHAR(50) CHARACTER SET WIN1251;
CREATE DOMAIN "COUNT1" AS SMALLINT
CHECK (VALUE >= 0);
CREATE DOMAIN "ID1" AS SMALLINT;
CREATE DOMAIN "MONEY" AS NUMERIC(8, 2)
DEFAULT 0
CHECK (VALUE > 0);
/* Table: AP_USERS, Owner: SYSDBA */
CREATE TABLE "AP_USERS"
(
"ID_USERS" "ID1" NOT NULL,
"NAME" "CHAR100" NOT NULL,
"EMAIL" "CHAR30" NOT NULL,
"PASS" "CHAR20" NOT NULL,
"CONTACTFIO" "CHAR30" NOT NULL,
"ID_COUNTRY" "ID1" NOT NULL,
"PINDEX" "CHAR10" NOT NULL,
"CITY" "CHAR20" NOT NULL,
"PADDRESS" "CHAR50" NOT NULL,
"PHONE" "CHAR12",
"FAX" "CHAR12",
"ETC" "CHAR50",
UNIQUE ("EMAIL"),
PRIMARY KEY ("ID_USERS")
);
/* Table: COUNTRIES, Owner: SYSDBA */
CREATE TABLE "COUNTRIES"
(
"ID_COUNTRY" "ID1" NOT NULL,
"COUNTRY" "CHAR20" NOT NULL,
CONSTRAINT "CONS2" UNIQUE ("COUNTRY"),
PRIMARY KEY ("ID_COUNTRY")
);
/* Table: KATEGORII, Owner: SYSDBA */
CREATE TABLE "KATEGORII"
(
"ID_KATEGOR" "ID1" NOT NULL,
"KATEGOR" "CHAR20" NOT NULL,
PRIMARY KEY ("ID_KATEGOR")
);
/* Table: LEK_LIST, Owner: SYSDBA */
CREATE TABLE "LEK_LIST"
(
"LEK_ID" "ID1" NOT NULL,
"ID_KATEGOR" "ID1" NOT NULL,
"NAZVZAN1" "CHAR30",
"NAZVZAN2" "CHAR30",
"NAZVZAN3" "CHAR50",
"CENA" "MONEY" NOT NULL,
PRIMARY KEY ("LEK_ID")
);
/* Table: SKLAD, Owner: SYSDBA */
CREATE TABLE "SKLAD"
(
"LEK_ID" "ID1" NOT NULL,
"OSTATOK" "COUNT1",
"STELLAJ" "CHAR20",
UNIQUE ("LEK_ID")
);
ALTER TABLE "AP_USERS" ADD FOREIGN KEY ("ID_COUNTRY") REFERENCES
COUNTRIES ("ID_COUNTRY");
ALTER TABLE "LEK_LIST" ADD FOREIGN KEY ("ID_KATEGOR") REFERENCES
KATEGORII ("ID_KATEGOR");
ALTER TABLE "SKLAD" ADD FOREIGN KEY ("LEK_ID") REFERENCES LEK_LIST
("LEK_ID");
CREATE GENERATOR "AP_USERS_ID";
CREATE GENERATOR "COUNTRIES_ID";
CREATE GENERATOR "KATEGORII_ID";
/* View: SPISOK1, Owner: SYSDBA */
CREATE VIEW "SPISOK1" (
"NAZVZAN1",
"OSTATOK",
"CENA"
) AS
SELECT NAZVZAN1, OSTATOK, CENA
FROM LEK_LIST, SKLAD
WHERE SKLAD.LEK_ID = LEK_LIST.LEK_ID
;
/* View: SPISOK2, Owner: SYSDBA */
CREATE VIEW "SPISOK2" (
"KATEGOR",
"NAZVZAN1",
"OSTATOK",
"CENA"
) AS
SELECT KATEGOR, NAZVZAN1, OSTATOK, CENA
FROM KATEGORII, LEK_LIST, SKLAD
WHERE (LEK_LIST.ID_KATEGOR = KATEGORII.ID_KATEGOR) AND
(SKLAD.LEK_ID = LEK_LIST.LEK_ID)
;
/* Exceptions */
CREATE EXCEPTION "NO_DEL_KAT" 'Нельзя удалять - есть лекарства этой категории';
CREATE EXCEPTION "NO_INS_LEK" 'Нельзя добавить - нет такой категории';
CREATE EXCEPTION "NO_UPD_KAT" 'Нельзя изменить - есть лекарства этой категории';
CREATE EXCEPTION "NO_UPD_LEK" 'Нельзя изменить - нет такой категории';
COMMIT WORK;
SET AUTODDL OFF;
SET TERM ^ ;
/* Stored procedures */
CREATE PROCEDURE "DELETE_LEKAR"
(
"LEKID" INTEGER
)
AS
BEGIN EXIT; END ^
CREATE PROCEDURE "INSERT_LEKAR"
(
"LEKID" INTEGER,
"IDKATEGOR" INTEGER,
"N1" VARCHAR(30) CHARACTER SET WIN1251,
"N2" VARCHAR(30) CHARACTER SET WIN1251,
"N3" VARCHAR(40) CHARACTER SET WIN1251,
"CENA" NUMERIC(8, 2)
)
AS
BEGIN EXIT; END ^
CREATE PROCEDURE "UPDATE_LEKAR"
(
"LEKID" INTEGER,
"IDKATEGOR" INTEGER,
"N1" VARCHAR(30) CHARACTER SET WIN1251,
"N2" VARCHAR(30) CHARACTER SET WIN1251,
"N3" VARCHAR(40) CHARACTER SET WIN1251,
"CENA" NUMERIC(8, 2)
)
AS
BEGIN EXIT; END ^
ALTER PROCEDURE "DELETE_LEKAR"
(
"LEKID" INTEGER
)
AS
BEGIN
DELETE FROM LEK_LIST
WHERE (LEK_ID = :LEKID);
END
^
ALTER PROCEDURE "INSERT_LEKAR"
(
"LEKID" INTEGER,
"IDKATEGOR" INTEGER,
"N1" VARCHAR(30) CHARACTER SET WIN1251,
"N2" VARCHAR(30) CHARACTER SET WIN1251,
"N3" VARCHAR(40) CHARACTER SET WIN1251,
"CENA" NUMERIC(8, 2)
)
AS
BEGIN
INSERT INTO LEK_LIST
VALUES (:LEKID, :IDKATEGOR, :N1, :N2, :N3, :CENA);
END
^
ALTER PROCEDURE "UPDATE_LEKAR"
(
"LEKID" INTEGER,
"IDKATEGOR" INTEGER,
"N1" VARCHAR(30) CHARACTER SET WIN1251,
"N2" VARCHAR(30) CHARACTER SET WIN1251,
"N3" VARCHAR(40) CHARACTER SET WIN1251,
"CENA" NUMERIC(8, 2)
)
AS
BEGIN
UPDATE LEK_LIST
SET
LEK_ID = :LEKID,
ID_KATEGOR = :IDKATEGOR,
NAZVZAN1 = :N1,
NAZVZAN2 = :N2,
NAZVZAN3 = :N3,
CENA = :CENA
WHERE LEK_ID = :LEKID;
END
^
SET TERM ; ^
COMMIT WORK;
SET AUTODDL ON;
SET TERM ^ ;
/* Triggers only will work for SQL triggers */
CREATE TRIGGER "SET_ID_CNTR" FOR "COUNTRIES"
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
new.ID_COUNTRY = gen_id(COUNTRIES_ID, 1);
END
^
CREATE TRIGGER "SET_ID_KATEGOR" FOR "KATEGORII"
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
new.ID_KATEGOR = gen_id(KATEGORII_ID, 1);
END
^
CREATE TRIGGER "BEFORE_DELETE_KAT" FOR "KATEGORII"
ACTIVE BEFORE DELETE POSITION 0
AS
DECLARE VARIABLE lek_count INTEGER ;
BEGIN
SELECT count(lek_id) from LEK_LIST
WHERE LEK_LIST.ID_KATEGOR = KATEGORII.ID_KATEGOR
INTO :lek_count ;
IF (:lek_count > 0) THEN EXCEPTION no_del_kat ;
END
^
CREATE TRIGGER "BEFORE_INSERT_LEK" FOR "LEK_LIST"
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE kat_count INTEGER;
BEGIN
SELECT count(ID_KATEGOR) from KATEGORII
WHERE KATEGORII.ID_KATEGOR = new.ID_KATEGOR
INTO :kat_count;
IF (:kat_count < 1) THEN EXCEPTION no_ins_lek;
END
^
CREATE TRIGGER "BEFORE_UPDATE_LEK" FOR "LEK_LIST"
ACTIVE BEFORE UPDATE POSITION 0
AS
DECLARE VARIABLE kat_count INTEGER;
BEGIN
SELECT count(ID_KATEGOR) from KATEGORII
WHERE KATEGORII.ID_KATEGOR = new.ID_KATEGOR
INTO :kat_count;
IF (:kat_count < 1) THEN EXCEPTION no_upd_lek;
END
^
COMMIT WORK ^
SET TERM ;^
/* Grant Roles for this database */
/* Grant permissions for this database */