Разработка базы данных из предметной области "Предприятие", страница 7

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

Решение проблемы мутирования:

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

Шаг 2. Создаем в основной таблице строчный триггер, который будет добавлять данные во временную таблицу, созданную на шаге 1.

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

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

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

           Код решения:

create or replace PACKAGE pk_emp_mgr AS

PROCEDURE set_start;

PROCEDURE add_comm(o_id Number, numb Number);

PROCEDURE check_undone;

END pk_emp_mgr;

CREATE OR REPLACE PACKAGE BODY pk_emp_mgr AS

und number;

iid Number;

w_t varchar2(2);

PROCEDURE set_start IS

BEGIN

und:=0;

iid:=0;

END set_start;

PROCEDURE add_comm(o_id Number, numb Number) IS

BEGIN

 iid:=o_id;

 und:=numb;

END add_comm;

PROCEDURE check_undone IS

emp number;

hou number;

CURSOR c_1 IS SELECT object_id FROM params WHERE number_value=iid and attr_id=11;

c_2 c_1%ROWTYPE;

BEGIN

emp:=iid;

OPEN c_1;

LOOP

FETCH c_1 into c_2 ;

EXIT WHEN c_1%NOTFOUND;

select text_value into w_t from params where object_id=emp and attr_id=6;

dbms_output.put_line(w_t);

IF w_t='F' THEN

BEGIN

UPDATE params SET number_value=und*0.76 WHERE attr_id=5 and object_id=c_2.object_id;

und:=und/0.76;

END;

ELSE

BEGIN

select number_value into hou from params where object_id=c_2.object_id and attr_id = 4;

und:=und*hou;

UPDATE params SET number_value=und*0.76 WHERE attr_id=5 and object_id=c_2.object_id;

und:=und/0.76;

und:=und/hou;

END;

END IF;

END LOOP;

CLOSE c_1;

END check_undone;

END pk_emp_mgr;

CREATE OR REPLACE TRIGGER  "EMP_COMM" AFTER UPDATE ON params

DECLARE

BEGIN

  pk_emp_mgr.check_undone;

END;

CREATE OR REPLACE TRIGGER  "TRG_TR_AR"

after update

on params

FOR EACH ROW

Begin

IF :new.attr_id=7 THEN

pk_emp_mgr.add_comm(:new.object_id,:new.number_value);

end if;

end;

CREATE OR REPLACE TRIGGER  "TRG_TR_BS"

before update

on params

begin

pk_emp_mgr.set_start;

end;

Код работает следующим образом:

1) В операторном триггере который срабатывает (или возбуждается, как написано в оригинальной инструкции к СУБД) before update выполняется зануление всех глобальный переменных;

2) В строчном триггере в эти глобальные переменные заносятся данные;

3) В операторном триггере создается курсор в который заносятся коды сотрудников которые соотвествуют коду должности в которой мы поменяли зарплату и в цыкле происходит обновление записи.

7.4 Заполнение таблиц метамодели

delete from params;

delete from objects;

delete from attributes;

delete from object_types;

/* Types */

insert into object_types values (1, 'emp', 'Employee');

insert into object_types values (2, 'job', 'Job');

insert into object_types values (3, 'dept', 'Department');