Oracle PL / SQL - пример триггера перед UPDATE
В этой статье показано, как использоватьBEFORE UPDATE TRIGGER, он срабатывает перед выполнением операции обновления. В сценариях реальной жизни он в основном используется для следующих целей:
-
Проверка данных
-
Обновлять значения автоматически
-
Регистрация данных или аудит
1. Проверка данных
Предположим, в некоторых компаниях есть вакансии и уже есть данные о заявках, а критерии следующие:
-
Опыт работы должен быть не менее 3 лет и
-
Предыдущая попытка подачи заявки не должна быть сделана в течение последних 2 лет.
Чтобы обеспечить целостность данных, мы создадим триггерBEFORE UPDATE, который ограничит ОБНОВЛЕНИЕ данными, которые нарушают любой из вышеуказанных критериев.
1.1 First, we will create table job_openings.
job_openings
--Creating job_openings table.
CREATE TABLE job_openings
(
APPLICATION_ID number(10) primary key,
FIRST_NAME varchar2(50),
LAST_NAME varchar2(50),
JOB_EXPERIENCE number(2),
LAST_APPLIED_DATE date
);
1.2 Then we will create a before update tigger on column JOB_EXPERIENCE and LAST_APPLIED_DATE of job_openings table.
trg_before_emp_update
-- Creating TRIGGER
CREATE OR REPLACE TRIGGER trg_before_emp_update
BEFORE UPDATE OF JOB_EXPERIENCE,LAST_APPLIED_DATE
on job_openings
FOR EACH ROW
DECLARE
years_since_last_applied number(5);
BEGIN
years_since_last_applied := -1;
IF(:NEW.LAST_APPLIED_DATE IS NOT NULL) THEN
SELECT MONTHS_BETWEEN(TO_DATE(sysdate,'DD-MON-YYYY'), TO_DATE(:NEW.LAST_APPLIED_DATE,'DD-MON-YYYY'))/12
INTO years_since_last_applied FROM dual;
-- Check whether years_since_last_applied is greater than 2 years or not
IF (years_since_last_applied <= 2) THEN
RAISE_APPLICATION_ERROR(-20000,'Previous application attempt must not be done in last 2 years.');
END IF;
END IF;
-- Job experience must be more than or equal to 3 years.
IF(:new.JOB_EXPERIENCE < 3) THEN
RAISE_APPLICATION_ERROR(-20000,'Job experience must be more than or equal to 3 years.');
END IF;
END;
1.3 Normal Data.
-- setting date format to to 'DD-MON-YYYY' alter session set nls_date_format = 'DD-MON-YYYY'; INSERT INTO job_openings VALUES (1,'Mark','Sharma',10,'01-JAN-2012'); INSERT INTO job_openings VALUES (2,'Praveen','Kumar',4,'01-DEC-2010'); INSERT INTO job_openings VALUES (3,'Rahul','Kohli',6,null); -- output 1 rows inserted. 1 rows inserted. 1 rows inserted.
select * from job_openings;
APPLICATION_ID |
ИМЯ |
ФАМИЛИЯ |
ОПЫТ РАБОТЫ |
LAST_APPLIED_DATE |
1 |
Mark |
Шарма |
10 |
01-ЯНВ-2012 |
2 |
Praveen |
Кумар |
4 |
01-ДЕК-2010 |
3 |
Рахул |
Коли |
6 |
null |
1.4 Test Trigger raise error – Job experience must be more than or equal to 3 years.
-- Try to update job_experience less than 3 years UPDATE job_openings SET JOB_EXPERIENCE = 2 where APPLICATION_ID = 1; -- error Error report - ORA-20000: Job experience must be more than or equal to 3 years. ORA-06512: at "SYSTEM.TRG_BEFORE_EMP_UPDATE", line 21 ORA-04088: error during execution of trigger 'SYSTEM.TRG_BEFORE_EMP_UPDATE'
1.5 Test Trigger raise error – Previous application attempt must not be done in last 2 years.
-- Try to update last_Applied_Date which is less than 2 years UPDATE job_openings SET LAST_APPLIED_DATE = '10-JUN-2016' where APPLICATION_ID = 3; -- error Error report - ORA-20000: Previous application attempt must not be done in last 2 years. ORA-06512: at "SYSTEM.TRG_BEFORE_EMP_UPDATE", line 15 ORA-04088: error during execution of trigger 'SYSTEM.TRG_BEFORE_EMP_UPDATE'
2. Обновить значения
Пример триггераBEFORE UPDATE для автоматического обновления:NEW.UPDATED_BY и:NEW.UPDATED_DATE.
2.1 Create a table.
person_records
--Creating person_records table.
CREATE TABLE person_records
(
PERSON_ID number(10) primary key,
FIRST_NAME varchar2(50),
LAST_NAME varchar2(50),
HIRE_DATE date,
UPDATED_BY varchar2(20),
UPDATED_DATE date
);
2.2 Create a before update trigger on table person_records
trg_before_person_update
CREATE OR REPLACE TRIGGER trg_before_person_update BEFORE UPDATE on person_records FOR EACH ROW DECLARE username varchar2(20); BEGIN SELECT USER INTO username FROM dual; -- Setting updated_by and updated_Date values. :NEW.UPDATED_BY := username; :NEW.UPDATED_DATE := sysdate; END;
2.3 Insert two records.
-- setting date format to to 'DD-MON-YYYY' alter session set nls_date_format = 'DD-MON-YYYY'; INSERT INTO person_records VALUES (101,'Devil','Khedut',sysdate,null,null); INSERT INTO person_records VALUES (102,'Kanji','Yadav',sysdate,null,null); -- output 1 rows inserted. 1 rows inserted.
select * from person_records;
PERSON_ID |
ИМЯ |
ФАМИЛИЯ |
ДАТА ПРИЕМА НА РАБОТУ |
UPDATED_BY |
UPDATED_DATE |
101 |
Дьявол |
Хедут |
06-ИЮН-2017 |
null |
null |
102 |
Kanji |
Ядав |
06-ИЮН-2017 |
null |
null |
2.4 Update records and it will fires the before update trigger. ЗначенияUPDATED_BY иUPDATED_DATE будут обновлены автоматически.
UPDATE person_records SET first_name = 'Lavji' WHERE person_id = 101; UPDATE person_records SET first_name = 'Jogi' WHERE person_id = 102; -- output 1 rows updated. 1 rows updated.
select * from person_records;
PERSON_ID |
ИМЯ |
ФАМИЛИЯ |
ДАТА ПРИЕМА НА РАБОТУ |
UPDATED_BY |
UPDATED_DATE |
101 |
Лавджи |
Хедут |
06-ИЮН-2017 |
HR |
06-ИЮН-2017 |
102 |
Jogi |
Ядав |
06-ИЮН-2017 |
HR |
06-ИЮН-2017 |
3. Logging/Auditing data
В этом примере мы создали триггер, который будет вставлять строки в таблицу аудита перед каждым обновлением таблицы транзакций. Каждый раз, когда пользователь ОБНОВЛЯЕТ данныеbank_transactions, старые данные будут вставлены вbank_transactions_audit триггером для аудита или резервного копирования.
3.1 Create a bank transaction table.
bank_transactions
--Creating bank_transactions table.
CREATE TABLE bank_transactions
(
TXN_ID number(10) primary key,
TXN_NUMBER varchar2(20),
PARTY_NAME varchar2(50),
TXN_DATE date,
CREATED_BY varchar2(20),
CREATED_DATE date
);
3.2 Create another bank transaction audit table.
bank_transactions_audit
--Creating bank_transactions_audit table.
CREATE TABLE bank_transactions_audit
(
TXN_ID number(10),
TXN_NUMBER varchar2(20),
PARTY_NAME varchar2(50),
TXN_DATE date,
CREATED_BY varchar2(20),
CREATED_DATE date
);
3.3 Create a before update trigger on bank_transactions table.
trg_before_update_txn_audit
--Creating Trigger
CREATE OR REPLACE TRIGGER trg_before_update_txn_audit
BEFORE UPDATE
ON bank_transactions
FOR EACH ROW
BEGIN
-- Insert OLD values in audit table for logging purpose
INSERT INTO bank_transactions_audit VALUES(:OLD.TXN_ID,:OLD.TXN_NUMBER,
:OLD.PARTY_NAME,:OLD.TXN_DATE,:OLD.CREATED_BY,:OLD.CREATED_DATE);
END;
3.4 Insert some records.
--Inserting values
INSERT INTO BANK_TRANSACTIONS values ('1','TXN1234','Peter Thomas','12-MAY-2017','HR',sysdate);
INSERT INTO BANK_TRANSACTIONS values ('2','TXN9999','Jemes Patel','10-JUN-2016','HR',sysdate);
select * from BANK_TRANSACTIONS;
TXN_ID |
TXN_NUMBER |
PARTY_NAME |
TXN_DATE |
СОЗДАН |
ДАТА СОЗДАНИЯ |
1 |
TXN1234 |
Питер Томас |
12-МАЯ-2017 |
HR |
06-ИЮН-2017 |
2 |
TXN9999 |
Джемес Патель |
10-ИЮН-2016 |
HR |
06-ИЮН-2017 |
3.5 Insert operation didn’t fire the before update trigger.
select * from BANK_TRANSACTIONS_AUDIT; -- output no rows selected.
3.6 Update records, it will fires the "before update" trigger and insert the old data into another audit table.
--updating values. UPDATE bank_transactions SET txn_number = 'NEWTXN8080' WHERE txn_id = 1; UPDATE bank_transactions SET txn_number = 'NEWTXN9595' WHERE txn_id = 2; -- output 1 rows updated. 1 rows updated.
select * from BANK_TRANSACTIONS;
TXN_ID |
TXN_NUMBER |
PARTY_NAME |
TXN_DATE |
СОЗДАН |
ДАТА СОЗДАНИЯ |
1 |
НОВЫЙTXN8080 |
Питер Томас |
12-МАЯ-2017 |
HR |
06-ИЮН-2017 |
2 |
НОВЫЙTXN9595 |
Джемес Патель |
10-ИЮН-2016 |
HR |
06-ИЮН-2017 |
select * from BANK_TRANSACTIONS_AUDIT;
TXN_ID |
TXN_NUMBER |
PARTY_NAME |
TXN_DATE |
СОЗДАН |
ДАТА СОЗДАНИЯ |
1 |
TXN1234 |
Питер Томас |
12-МАЯ-2017 |
HR |
06-ИЮН-2017 |
2 |
TXN9999 |
Джемес Патель |
10-ИЮН-2016 |
HR |
06-ИЮН-2017 |
Рекомендации
-
https://docs.oracle.com/cloud/latest/db112/LNPLS/create_trigger.htm#LNPLS01374 [Oracle
-
Заявление CREATE TRIGGER]
-
-
https://docs.oracle.com/cloud/latest/db112/LNPLS/triggers.htm#LNPLS020 [Oracle
-
PL/SQL Triggers]
-