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]
-