Попробуйте составной триггер:
CREATE OR REPLACE TRIGGER compound_trigger_name
FOR INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
BEFORE EACH ROW IS
BEGIN
-- collect updated or inserted departments
Departments(:new.department) := :new.department;
END BEFORE EACH ROW;
AFTER STATEMENT IS
sum_sal NUMBER;
BEGIN
-- for each updated department check the restriction
FOR dept IN Departments.FIRST .. Departments.LAST
LOOP
SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
IF sum_sal > 1000 THEN
raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
END IF;
END LOOP;
END AFTER STATEMENT;
END compound_trigger_name;
/
======== EDIT - несколько вопросов и ответы ===========
В: Почему возникает ошибка с изменением таблицы?
A: Это описано в документации:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708
Trigger Ограничения на мутирует таблицах
Таблица Mutating представляет собой таблицу , которая модифицируется с помощью UPDATE, DELETE или INSERT заявление , или таблицу , которая может быть обновлена эффектами ограничения DELETE CASCADE .
Сессия, которая выдала триггерный оператор, не может запросить или изменить мутирующую таблицу. Это ограничение предотвращает триггер от , видя несогласованный набор данных.
Данное ограничение распространяется на все триггеры, которые используют предложение FOR EACH ROW . Представления, измененные в триггерах INSTEAD OF, не считаются мутированием.
Когда триггер встречает таблицу мутирует, возникает ошибка времени выполнения, эффекты тела триггера и триггера прокатывают назад, и управление возвращается к пользователю или приложению. (Вы можете использовать составные триггеры , чтобы избежать ошибки с ошибкой.Для получения дополнительной информации приведена в разделе Использование соединения Триггеры избежать мутирует СТОЛ Error)
. Q: Как избежать ошибки Mutating таблицы?
A: документация рекомендует использовать триггер coumpound, увидеть это: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ
Используя соединение Триггеры, чтобы избежать Mutating-Table Ошибка Вы можете использовать соединение триггеров, чтобы избежать ошибки Mutating-таблицы (ORA-04091) , описанный в разделе Ограничения триггера на мутационных таблицах.
Q: Что такое триггер соединение и как это работает?
A: Это огромная тема, пожалуйста, обратитесь к документации здесь: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD
Короче говоря: это особый вид триггера, который делает psiible объединить четыре типа отдельных триггеров: BEFORE statement
, BEFORE-for each row
, AFTER for each row
и AFTER statament
в одно объявление. Это упрощает реализацию некоторых сценариев, в которых необходимо передавать некоторые данные с одного триггера на другой. Пожалуйста, изучите приведенную выше ссылку для получения более подробной информации.
Q: Но что на самом деле делает "Departments(:new.department) := :new.department;
?
A: В этом объявлении хранится номер отдела в ассоциативный массив.
Этот массив объявлен в декларативной части составного триггера:
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
документация, связанная с соединением триггеров говорит, что: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE
Опциональная декларативная часть (первая часть) объявляет переменные и , которые могут использовать подпрограммы, которые могут использовать секторы временной точки. Когда срабатывает триггер , декларативная часть выполняется до того, как будут выполнены кадры с временными точками . Переменные и подпрограммы, объявленные в этом разделе, имеют продолжительность стрельбы.
Вышеупомянутое означает, что переменная Departments
инициализируется только один раз в начале всей обработки, сразу после срабатывания триггера. «Длительность прогоновки» означает, что эта переменная разрушается после завершения триггера.
Это заявление: Departments(:new.department) := :new.department;
хранит номер отдела в ассоциативном массиве. Он находится в разделе BEFORE EACH ROW
, затем выполняется для каждой строки, которая обновляется (или вставлена) оператором update/insert.
:new
и :old
являются псевдозаписями, больше на них вы можете найти здесь: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Короче: :new.department
получает новое значение department
столбцов для в настоящее время обновляется строка (обновленное значения - после обновления), в то время как :old.department
дает старый значение этого столбца (ПЕРЕД обновлением).
Эта коллекция впоследствии используется в AFTER STATEMENT
, когда TRIGERS выбрать все обновленные отделы (в FOR-LOOP), для каждого departmens пожаров SELECT SUM(salary) ...
и затем проверяет, если эта сумма меньше, чем 1000
Рассмотрим простое обновление: UPDATE treballa SET salary = salary + 10
. Это один оператор обновления, но он меняет сразу несколько строк. Порядок исполнения нашего триггера следующим образом:
- statament обновления обжигают:
UPDATE treballa SET salary = salary + 10
- декларативная часть триггера выполняется, то есть:
Departments
переменные инициализируются
BEFORE EACH ROW
секции выполняются , отдельно для каждой обновленной строки - столько раз, сколько есть строк для обновления. В этом месте мы собираем все отделы из измененных строк.
AFTER STATEMENT
раздел выполнен. На этом этапе таблица уже обновлена - все строки уже имеют новые обновленные зарплаты. Мы проводим цикл в отделах, сохраненных в Departments
, и для каждого из них мы проверяем, равна ли сумма зарплат меньше или равна 1000. Если эта сумма составляет> 1000 для любого из этих отделов, тогда возникает ошибка, и все обновление прерывается и свернуто назад. В противном случае триггер завершится, и обновление будет выполнено (но вам все равно необходимо зафиксировать эти изменения).
Q: Что представляет собой ассоциативный массив, и почему именно используется этот вид коллекции, а не других коллекций (в VARRAY или вложенной таблицы)?
A: Коллекции PL/SQL - огромная тема. Перейдите по этой ссылке, чтобы узнать их: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005
Короче - ассоциативный массив (или индекс-таблицы), как карты в Java (HashMap, древовидные карты и т.д.) - это набор пар ключ-значение, и каждый ключ уникален. Вы можете поместить один и тот же ключ много раз в этот массив (с разными значениями), но этот ключ будет храниться только один раз - он уникален.
Я использовал его, чтобы получить уникальный набор отделов.
Рассмотрим пример нашего обновления: UPDATE treballa SET salary = salary + 10
- эта команда касается сотен строк, имеющих один и тот же отдел. Я не хочу, чтобы коллекция с тем же отделом дублировалась 100 раз, мне нужен уникальный набор отделов, и я хочу выполнить наш запрос SELECT sum()...
только один раз для каждого отдела, а не 100 раз. С помощью sssociative массива это делается автоматически - я получаю уникальный набор отступов.
Это для реального применения? Или домашнее задание? Предполагая, что это домашнее задание, рассказал ли ваш инструктор об исключении мутирующей таблицы? Это невозможно реализовать с помощью одного триггера, что было бы крайне неприемлемым в реальной системе. Чтобы сделать это правильно, вам понадобится несколько триггеров (или составной триггер с несколькими разделами). –
Является домашним заданием, учитель не говорил об этом, когда я пытаюсь сделать этот триггер по-своему, Oracle дает мне ошибку, похожую на «таблица мутирует ...» Извините, я не на переднем плане ПК теперь, но мне просто нужно знать, какой рабочий был отредактирован, чтобы снова пересчитать зарплату ... –
Измените свой вопрос, включив триггер, который вы написали, и полученную вами ошибку. –