2020년 7월 19일 일요일

오라클 트리거(Oracle Trigger), 트리거실행순서, Instead Of Trigger, Trigger Mutating Table Exception, Compound Triggers, Trigger Enable/Disable/Drop

오라클 트리거(Oracle Trigger), 트리거실행순서, Instead Of Trigger, Trigger Mutating Table Exception, Compound Triggers, Trigger Enable/Disable/Drop

http://ojc.asia/bbs/board.php?bo_table=LecSQLnPlSql&wr_id=585

9. 트리거(Trigger)

9.1 트리거 개요, 기본문법

n 트리거링 이벤트에 대해 자동으로 실행되는 프로시저로 데이터베이스에 저장되는 스키마 오브젝트 이다.

n 트리거링 이벤트

데이터 조작어(DML, Data Manipulation Language) : INSERT, UPDATE, DELETE

데이터 정의어(DDL, Data Definition Language) : CREATE, ALTER, DROP

데이터베이스 오퍼레이션 : SERVERERROR, LOGON, STARTUP or SHUTDOWN

n 트리거 타이밍

BEFORE : 이벤트가 발생하기 전에

AFTER : 이벤트가 발생한 후에

n FOR EACH ROW : DML의 영향을 받는 모든 행, 레코드마다 트리거가 작동되는 트리거를 행 트리거라고 하며 몇건의 데이터가 삽입, 삭제, 갱신되더라도 한번만 동작하는 트리거를 명령문 트리거라고 한다.

n FOR EACH ROW절이 있다면 행 트리거이고 행 트리거에 한해 레코드의 값을 제어할 수 있다.

:old : UPDATE 되기전의 값, DELETE 되기전의 값에 접근 가능

:new : INSERT 되는 값, UPDATE된 후의 값에 접근 가능

만약 :old, :new 대신 다른 키워드를 사용하려면 아래처럼 하면 된다.

CREATE OR REPLACE TRIGGER salary_change

BEFORE UPDATE ON EMP

REFERENCING new AS n old AS o

FOR EACH ROW

BEGIN

......

dbms_output.put_line(:n.ename);

END;

n WHEN : WHEN절에 조건을 줘서 조건에 맞는 경우에만 트리거가 동작되도록 할 수 있다.

CREATE [ OR REPLACE ] TRIGGER trigger_name

[타이밍 AFTER/BEFORE] [이벤트1] [OR 이벤트2] ……

ON table_name

[ FOR EACH ROW ] -- 행트리거 여부를 결정, DML의 영향을 받는 레코드마다 트리거동작

[WHEN 조건]

DECLARE

선언부

BEGIN

-- 트리거 실행 코드

EXCEPTION

END;

--주말 오전10시에서 오후 6시 사이 EMP 테이블에 DML 사용못하게 하는 트리거

--아래는 명령문 트리거, 여러건이 DML의 영향을 받더라도 한번만 실행

SQL> create or replace trigger chk_emp_dml

before insert or update or delete on emp

begin

if ((to_char(sysdate,'DY') in ('토','일')) AND

(to_number(to_char(sysdate,'HH24'))) >= 10 AND

(to_number(to_char(sysdate,'HH24'))) <= 18) THEN

raise_application_error(-20001,'주말변경불가합니다.');

end if;

end;

/

트리거가 생성되었습니다.

SQL> update emp set sal = 0;

update emp set sal = 0

*

1행에 오류:

ORA-20001: 주말변경불가합니다.

ORA-06512: "SCOTT.CHK_EMP_DML", 5행

ORA-04088: 트리거 'SCOTT.CHK_EMP_DML'의 수행시 오류

SQL> DROP TRIGGER chk_emp_dml;

-- 명령문 트리거 예제, FOR EACH ROW절이 없다.

SQL> CREATE OR REPLACE TRIGGER CHK_EMP

BEFORE INSERT OR UPDATE OF ename, sal OR DELETE ON emp

BEGIN

CASE

WHEN INSERTING THEN

DBMS_OUTPUT.PUT_LINE('Inserting...');

WHEN UPDATING('sal') THEN

DBMS_OUTPUT.PUT_LINE('Updating sal...');

WHEN UPDATING('ename') THEN

DBMS_OUTPUT.PUT_LINE('Updating ename...');

WHEN DELETING THEN

DBMS_OUTPUT.PUT_LINE('Deleting...');

END CASE;

END;

/

트리거가 생성되었습니다.

SQL> SET SERVEROUTPUT ON

SQL> insert into emp (empno, ename) values (88, '88길동');

Inserting...

1 개의 행이 만들어졌습니다.

SQL> delete from emp where empno = 88;

Deleting...

1 행이 삭제되었습니다.

SQL> update emp set sal = sal + 10 where empno = 7369;

Updating sal...

1 행이 갱신되었습니다.

SQL> update emp set ename = '오자바커' where empno = 7369;

Updating ename...

1 행이 갱신되었습니다.

-- 행트리거 예제, FOR EACH ROW절이 있다.

SQL> create table emp_bak (

old_sal number,

new_sal number,

u_date date,

action varchar2(20));

테이블이 생성되었습니다.

SQL> create or replace trigger tr_emp_update

after update of sal on emp

for each row

begin

insert into emp_bak values (:old.sal, :new.sal, sysdate,'UPDATE');

end;

/

트리거가 생성되었습니다.

-- EMP테이블의 전체 레코드 24건에 대해 트리거가 발행된다.

SQL> update emp set sal = sal + 500;

Updating sal...

24 행이 갱신되었습니다.

SQL> select * from emp_bak;

OLD_SAL NEW_SAL U_DATE ACTION

---------- ---------- -------- --------------------

800 1300 15/02/28 UPDATE

1600 2100 15/02/28 UPDATE

……

7777 8277 15/02/28 UPDATE

9998 10498 15/02/28 UPDATE

SQL> DROP TRIGGER CHK_EMP;

-- WHEN절을 이용하여 조건이 맞는 경우에만 트리거가 동작하도록 할 수 있다.

SQL> CREATE OR REPLACE TRIGGER print_emp

BEFORE UPDATE ON emp

FOR EACH ROW

WHEN (new.sal > 500)

DECLARE

sal_diff number;

BEGIN

sal_diff := :new.sal - :old.sal;

dbms_output.put('OLD SALARY : ' || :old.sal);

dbms_output.put(',NEW SALARY : ' || :new.sal);

dbms_output.put_line(',급여차이 ' || sal_diff);

END;

/

트리거가 생성되었습니다.

SQL> set serveroutput on

SQL> update emp set sal = 0;

14 행이 갱신되었습니다.

SQL> rollback;

롤백이 완료되었습니다.

SQL> update emp set sal = 501;

OLD SALARY : 800,NEW SALARY : 501,급여차이 -299

……

OLD SALARY : 1300,NEW SALARY : 501,급여차이 -799

14 행이 갱신되었습니다.

SQL> DROP TRIGGER print_emp;

[LAB]

1. EMP 테이블에 데이터가 입력되면 EMP_OLD 테이블이 있다면 이 테이블에 insert

없다면 EMP_OLD 테이블을 만들고 이 테이블에 insert하는 행 레벨 트리거를 작성하세요.

(입력되는 sal값이 3000보다 큰 경우에만 트리거 동작하도록)

트리거에서 create table 하는 방법에 대해 고민해 보세요!

2. EMP 테이블의 sal 칼럼에 변경이 일어나는 경우 sal_log 테이블의

empno, old_sal, new_sal, up_date(현재 날짜 입력) 칼럼에 값을 입력하고

ename 칼럼에 변경이 일어나는 경우 ename_log 테이블의

empno, old_ename, new_ename, up_date(현재 날짜 입력) 칼럼에 값을 입력하세요.

sal_log 및 ename_log 테이블은 각각 생성 하세요.

3. 'OJC1' 사용자로 로그인을 막는 Trigger를 작성하세요.

- 로그온을 막을 USER는 DBA권한을 가져서는 안된다.

- 이러한 트리거를 시스템 트리거라고 하며 SYS계정에서는 생성할 수 없으며 SYSTEM 계정 또는 DB의 로컬 관리자로 들어가서 만들어야 한다.

9.2 Setting Trigger Order

n 오라클에서 동일한 트리거링 이벤트, 타이밍에 대해 여러 개의 트리거를 작성하는 것은 가능하다.

n Oracle 11g 이후 동일한 트리거링 이벤트 및 트리거 타이밍에 대해 실행되는 트리거가 여러 개인 경우 FOLLOWS, PRECEDES 구를 통해 실행의 우선 순위를 정하는 것이 가능해 졌다.

[형식]

CREATE OR REPLACE TRIGGER [TRIGGER TO FOLLOW]

[TIMING SPECIFICATION]

[EVENT SPECIFICATION]

FOLLOWS [TRIGGER TO BE FOLLOWED]

SQL> SET SERVEROUTPUT ON

SQL> CREATE OR REPLACE TRIGGER tr_follows_test1

BEFORE UPDATE ON emp

FOR EACH ROW

BEGIN

DBMS_OUTPUT.put_line('tr_follows_test1 실행...');

END;

/

트리거가 생성되었습니다.

SQL> CREATE OR REPLACE TRIGGER tr_follows_test2

BEFORE UPDATE ON emp

FOR EACH ROW

BEGIN

DBMS_OUTPUT.put_line('tr_follows_test2 실행...');

END;

/

트리거가 생성되었습니다.

SQL> update emp set sal = 9999 where ename = 'KING';

tr_follows_test2 실행...

tr_follows_test1 실행...

SQL> CREATE OR REPLACE TRIGGER tr_follows_test2

BEFORE UPDATE ON emp

FOR EACH ROW

FOLLOWS tr_follows_test1

BEGIN

DBMS_OUTPUT.put_line('tr_follows_test2 실행...');

END;

/

트리거가 생성되었습니다.

SQL> update emp set sal = 9999 where ename = 'KING';

tr_follows_test1 실행...

tr_follows_test2 실행...

9.3 Instead Of Trigger

n 여러 테이블로 이루어진 뷰에 DML이 가해질 때 대신 trigger를 동작시킬 수 있는데 이때 사용하는 것이 instead of trigger 이다.

SQL> drop table employee;

테이블이 삭제되었습니다.

SQL> drop table department;

테이블이 삭제되었습니다.

SQL > CREATE TABLE department (

deptno NUMBER PRIMARY KEY,

deptname VARCHAR2(20),

manager_num NUMBER

);

SQL> CREATE TABLE employee (

empno NUMBER PRIMARY KEY,

empname VARCHAR2(20),

deptno NUMBER REFERENCES department(deptno),

startdate DATE

);

SQL> CREATE OR REPLACE VIEW manager_info AS SELECT d.deptno, d.deptname, e.empno, e.empname

FROM employee e, department d

WHERE e.empno = d.manager_num;

SQL> CREATE OR REPLACE TRIGGER manager_info_insert

INSTEAD OF INSERT ON manager_info

FOR EACH ROW

DECLARE

employeeCount NUMBER;

BEGIN

SELECT COUNT(*) INTO employeeCount

FROM employee e

WHERE e.deptno = :new.deptno;

IF employeeCount >= 1 THEN

UPDATE department d

SET manager_num = :new.empno

WHERE d.deptno = :new.deptno;

insert into employee (empno, empname, deptno, startdate)

values (:new.empno, :new.empname, :new.deptno, sysdate);

ELSE

insert into department(deptno, deptname, manager_num)

values (:new.deptno, :new.deptname, 0);

insert into employee (empno, empname, deptno, startdate)

values (:new.empno, :new.empname, :new.deptno, sysdate);

END IF;

END;

/

SQL> INSERT INTO manager_info VALUES (11,'SALES',1004,'ANGEL');

1 개의 행이 만들어졌습니다.

SQL> INSERT INTO manager_info VALUES (11,'SALES',1005,'SUJI');

1 개의 행이 만들어졌습니다.

SQL> commit;

커밋이 완료되었습니다.

SQL> SELECT * FROM department;

DEPTNO DEPTNAME MANAGER_NUM

---------- -------------------- -----------

11 SALES 1005

SQL> SELECT * FROM employee;

EMPNO EMPNAME DEPTNO STARTDAT

---------- -------------------- ---------- --------

1004 ANGEL 11 16/05/01

1005 SUJI 11 16/05/01

SQL> INSERT INTO manager_info VALUES (21,'RND',1006,'SMITH');

1 개의 행이 만들어졌습니다.

SQL> SELECT * FROM department;

DEPTNO DEPTNAME MANAGER_NUM

---------- -------------------- -----------

11 SALES 1005

21 RND 0

SQL> SELECT * FROM employee;

EMPNO EMPNAME DEPTNO STARTDAT

---------- -------------------- ---------- --------

1004 ANGEL 11 16/05/01

1005 SUJI 11 16/05/01

1006 SMITH 21 16/05/01

SQL> SELECT * FROM manager_info;

DEPTNO DEPTNAME EMPNO EMPNAME

---------- -------------------- ---------- --------

11 SALES 1005 SUJI

9.4 Trigger Mutating Table Exception, Compound Triggers

n Mutating Table Exception : 행레벨 트리거(Row-Level Trigger)에서 변하고 있는 값을 참조하거나 변경하려고 할 때 발생되는 오류(ORA-04091: table XXX is mutating, trigger/function may not see it)

n Mutating 에러는 Insert, Update, Delete와 같은 DML이 수행되고 여기에 연결되어 있는 행레벨 트리거에서 변하는 값을 참조하는 경우 발생하는 오류이다.

n Mutating 에러는 Compund Trigger를 이용하여 해결할 수 있는데 하나의 트리거에 여러 개의 트리거링 타이밍을 기술하려면 COMPOUND TRIGGER구를 사용한다.

n 개별 트리거링 타이밍에서 밖에서 선언한 전역 변수에 대해 참조가 가능하므로 행 레벨 트리거에서 변하는 값들을 전역 변수(주로 배열처럼 쓰이는 테이블 타입의 컬렉션 변수)에 저장한 후 명령문 레벨 트리거의 AFTER 타이밍에서 한번에 처리함으로써 트리거에서 변하고 있는 값을 참조하는 경우 자주 발생하는 ORA-04091 에러를 방지할 수 있다.

[Compound Trigger 형식]

CREATE OR REPLACE TRIGGER 컴파운드_트리거이름

FOR 트리거링 이벤트 ON 테이블명

COMPOUND TRIGGER

-- 전역 변수 선언

g_global_variable VARCHAR2(10);

BEFORE STATEMENT IS --명령문 레벨 트리거 BEFORE

BEGIN

NULL; -- Do something here.

END BEFORE STATEMENT;

BEFORE EACH ROW IS --행레벨 트리거 BEFORE

BEGIN

NULL; -- Do something here.

END BEFORE EACH ROW;

AFTER EACH ROW IS --행레벨 트리거 AFTER

BEGIN

NULL; -- Do something here.

END AFTER EACH ROW;

AFTER STATEMENT IS --명령문 레벨 트리거 AFTER

BEGIN

NULL; -- Do something here.

END AFTER STATEMENT;

END <trigger-name>;

/

1. 행레벨 트리거가 변하는 값을 참조하는 경우

CREATE OR REPLACE TRIGGER emp_trigger

AFTER INSERT ON emp

FOR EACH ROW -- 행레벨 트리거

DECLARE

cnt NUMBER;

BEGIN

SELECT count(*)

INTO cnt

FROM emp;

dbms_output.put_line('전체 사원수 : ' || cnt);

END;

/

SQL> insert into emp (empno, ename) values (3333,'8길동');

insert into emp (empno, ename) values (3333,'8길동')

*

1행에 오류:

ORA-04091: SCOTT.EMP 테이블이 변경되어 트리거/함수가 볼 수 없습니다.

ORA-06512: "SCOTT.EMP_TRIGGER", 4행

ORA-04088: 트리거 'SCOTT.EMP_TRIGGER'의 수행시 오류

2. ORA-04091을 방지하기 위해 명령문 레벨 트리거로 변경

CREATE OR REPLACE TRIGGER emp_trigger

AFTER INSERT ON emp

-- FOR EACH ROW -- 행레벨 트리거

DECLARE

cnt NUMBER;

BEGIN

SELECT count(*)

INTO cnt

FROM emp;

dbms_output.put_line('전체 사원수 : ' || cnt);

END;

/

SQL> insert into emp (empno, ename) values (3333,'8길동');

전체 사원수 : 17

1 개의 행이 만들어졌습니다.

SQL> rollback;

3. pragma autonomous transaction 을 이용

:: DML이 일어나는 세션의 트랜잭션과는 별개로 동작

CREATE OR REPLACE TRIGGER emp_trigger

AFTER INSERT ON emp

FOR EACH ROW -- 행레벨 트리거

DECLARE

PRAGMA AUTONOMOUS_TRANSACTION;

cnt NUMBER;

BEGIN

SELECT count(*)

INTO cnt

FROM emp;

dbms_output.put_line('전체 사원수 : ' || cnt);

END;

/

-- 트리거을 일으킨 트랜잭션이 종료되지 않아 입력된 건은 반영되지 않는다.

SQL> select count(*) from emp;

COUNT(*)

----------

17

SQL> insert into emp (empno, ename) values (4444,'9길동');

전체 사원수 : 17

1 개의 행이 만들어졌습니다.

SQL> rollback;

4. Compound Trigger 이용

CREATE OR REPLACE TRIGGER emp_trigger

FOR INSERT or UPDATE

ON emp

COMPOUND TRIGGER

/* Declaration Section*/

cnt NUMBER;

-- 행 레벨

AFTER EACH ROW IS

BEGIN

dbms_output.put_line('Insert/Update is Completed');

END AFTER EACH ROW;

-- 명령문 레벨

AFTER STATEMENT IS

BEGIN

SELECT count(*)

INTO cnt

FROM emp;

dbms_output.put_line('전체 사원수 : ' || cnt);

END AFTER STATEMENT;

END emp_trigger;

/

SQL> select count(*) from emp;

COUNT(*)

----------

18

SQL> insert into emp (empno, ename) values (7777,'7길동');

Insert/Update is Completed

전체 사원수 : 19

1 개의 행이 만들어졌습니다.

SQL> rollback;

--------------------------------------------------------------------------------

-- Mutating Table Exception 예제

--------------------------------------------------------------------------------

SQL> CREATE TABLE tr_test2 (

id NUMBER(10) primary key,

name VARCHAR2(50)

);

테이블이 생성되었습니다.

SQL> CREATE SEQUENCE tr_test2_seq;

시퀀스가 생성되었습니다.

SQL> CREATE TABLE tr_test2_log (

id NUMBER(10) primary key,

action VARCHAR2(10) NOT NULL,

tr_test2_id NUMBER(10),

count NUMBER(5),

cr_date TIMESTAMP

);

테이블이 생성되었습니다.

SQL> ALTER TABLE tr_test2_log ADD (

CONSTRAINT tr_test2_fk FOREIGN KEY (tr_test2_id)

REFERENCES tr_test2(id)

);

테이블이 변경되었습니다.

SQL> CREATE SEQUENCE tr_test2_log_seq;

시퀀스가 생성되었습니다.

-- 패키지 명세

SQL> CREATE OR REPLACE PACKAGE tr_test2_pkg IS

PROCEDURE tr_test2_change (p_id IN tr_test2.id%TYPE,

p_action IN VARCHAR2);

END tr_test2_pkg;

/

패키지가 생성되었습니다.

-- 패키지 바디

SQL> CREATE OR REPLACE PACKAGE BODY tr_test2_pkg IS

PROCEDURE tr_test2_change (p_id IN tr_test2.id%TYPE,

p_action IN VARCHAR2)

IS

cnt NUMBER(5) := 0;

BEGIN

SELECT COUNT(*)

INTO cnt

FROM tr_test2;

INSERT INTO tr_test2_log

VALUES (tr_test2_log_seq.NEXTVAL, p_action, p_id, cnt, SYSTIMESTAMP);

END tr_test2_change;

END tr_test2_pkg;

/

패키지 본문이 생성되었습니다.

SQL> CREATE OR REPLACE TRIGGER tr_test2_trigger

AFTER INSERT OR UPDATE ON tr_test2

FOR EACH ROW

BEGIN

IF inserting THEN

tr_test2_pkg.tr_test2_change(p_id => :new.id, p_action => 'INSERT');

ELSE

tr_test2_pkg.tr_test2_change(p_id => :new.id, p_action => 'UPDATE');

END IF;

END;

/

트리거가 생성되었습니다.

-- tr_test2에 after insert 트리거가 동작을 하는데 자기자신 테이블의 레코드건수를 count(*)

-- 변하는 값을 참조하므로 4091오류 발생

SQL> INSERT INTO tr_test2 (id, name) VALUES (tr_test2_seq.NEXTVAL, 'OJC');

INSERT INTO tr_test2 (id, name) VALUES (tr_test2_seq.NEXTVAL, 'OJC')

*

1행에 오류:

ORA-04091: SCOTT.TR_TEST2 테이블이 변경되어 트리거/함수가 볼 수 없습니다.

ORA-06512: "SCOTT.TR_TEST2_PKG", 7행

ORA-06512: "SCOTT.TR_TEST2_TRIGGER", 3행

ORA-04088: 트리거 'SCOTT.TR_TEST2_TRIGGER'의 수행시 오류

[해결책]

-- 행 레벨 트리거와 명령문 트리거를 조합하여 해결

-- tr_test2_pkg 패키지에 명령문 트리거에서 호출할 프로시저 추가

-- PL/SQL 데이터 타입중 TABLE TYPE(배열처럼 쓰이는 것)을 이용하여 행 단위 트리거에서

-- 발생하는 데이터를 저장 후 명령문 트리거에서 일괄적으로 삽입하여 해결

SQL> CREATE OR REPLACE PACKAGE tr_test2_pkg AS

PROCEDURE tr_test2_change (p_id IN tr_test2.id%TYPE,

p_action IN VARCHAR2);

PROCEDURE tr_test2_statement_change;

END tr_test2_pkg;

/

패키지가 생성되었습니다.

SQL> CREATE OR REPLACE PACKAGE BODY tr_test2_pkg AS

TYPE type_change_rec IS RECORD (

id tr_test2.id%TYPE,

action tr_test2_log.action%TYPE

);

TYPE type_change_tab IS TABLE OF type_change_rec;

g_change_tab type_change_tab := type_change_tab();

PROCEDURE tr_test2_change (p_id IN tr_test2.id%TYPE,

p_action IN VARCHAR2)

IS

BEGIN

g_change_tab.extend;

g_change_tab(g_change_tab.last).id := p_id;

g_change_tab(g_change_tab.last).action := p_action;

END tr_test2_change;

PROCEDURE tr_test2_statement_change IS

cnt NUMBER(10);

BEGIN

FOR i IN g_change_tab.first .. g_change_tab.last LOOP

SELECT COUNT(*)

INTO cnt

FROM tr_test2;

INSERT INTO tr_test2_log

VALUES (tr_test2_log_seq.NEXTVAL, g_change_tab(i).action,

g_change_tab(i).id, cnt, SYSTIMESTAMP);

END LOOP;

g_change_tab.delete;

END tr_test2_statement_change;

END tr_test2_pkg;

/

패키지 본문이 생성되었습니다.

-- 새로 추가한 프러시저(tr_test2_statement_change)를

-- 호출하기 위한 명령문 레벨 트리거를 추가하자.

SQL> CREATE OR REPLACE TRIGGER tr_test2_trigger2

AFTER INSERT OR UPDATE ON tr_test2

BEGIN

tr_test2_pkg.tr_test2_statement_change;

END;

/

트리거가 생성되었습니다.

SQL> INSERT INTO tr_test2 (id, name) VALUES (tr_test2_seq.NEXTVAL, 'OJC');

1 개의 행이 만들어졌습니다.

------------------------------------------------------------------------------------------

앞에서 작성한 Mutating Table Exception을 Compound Trigger를 이용해결

------------------------------------------------------------------------------------------

SQL> drop trigger tr_test2_trigger;

트리거가 삭제되었습니다.

SQL> drop trigger tr_test2_trigger2;

트리거가 삭제되었습니다.

SQL> CREATE OR REPLACE TRIGGER tr_test2_compound_trigger

FOR INSERT OR UPDATE ON tr_test2

COMPOUND TRIGGER

TYPE type_change_tab IS TABLE OF tr_test2_log%ROWTYPE;

g_change_tab type_change_tab := type_change_tab();

AFTER EACH ROW IS

BEGIN

g_change_tab.extend;

g_change_tab(g_change_tab.last).id := tr_test2_log_seq.NEXTVAL;

IF INSERTING THEN

g_change_tab(g_change_tab.last).action := 'INSERT';

ELSE

g_change_tab(g_change_tab.last).action := 'UPDATE';

END IF;

g_change_tab(g_change_tab.last).tr_test2_id := :new.id;

g_change_tab(g_change_tab.last).cr_date := SYSTIMESTAMP;

END AFTER EACH ROW;

AFTER STATEMENT IS

BEGIN

FOR i IN g_change_tab.first .. g_change_tab.last LOOP

SELECT COUNT(*)

INTO g_change_tab(i).count

FROM tr_test2;

END LOOP;

FORALL i IN g_change_tab.first .. g_change_tab.last

INSERT INTO tr_test2_log VALUES g_change_tab(i);

g_change_tab.delete;

END AFTER STATEMENT;

END tr_test2_compound_trigger;

/

트리거가 생성되었습니다.

SQL> INSERT INTO tr_test2 (id, name) VALUES (tr_test2_seq.NEXTVAL, 'OJC');

1 개의 행이 만들어졌습니다.

9.5 Trigger Enable/Disable/Drop

n 작성된 트리거는 활성화/비활성화가 가능하다.

n 오라클 11g 이후 트리거를 만들때도 활성화/비활성화 설정이 가능하다.

n Drop Trigger 명령으로 트리거 삭제가 가능하다.

[형식]

ALTER TRIGGER 트리거이름 DISABLE;

ALTER TRIGGER 트리거이름 ENABLE;

ALTER TABLE 테이블이름 DISABLE ALL TRIGGERS;

ALTER TABLE 테이블이름 ENABLE ALL TRIGGERS;

DROP TRIGGER 트리거이름;

SQL> SET SERVEROUTPUT ON

SQL> CREATE OR REPLACE TRIGGER tr_emp_test

BEFORE INSERT or UPDATE ON emp

FOR EACH ROW

ENABLE

BEGIN

DBMS_OUTPUT.put_line('tr_emp_test 실행...');

END;

/

트리거가 생성되었습니다.

SQL> insert into emp (empno, ename, sal, deptno)

2 values (7676, '오자바커', 8000, 20);

tr_emp_test 실행...

SQL> CREATE OR REPLACE TRIGGER tr_emp_test

BEFORE INSERT or UPDATE ON emp

FOR EACH ROW

DISABLE

BEGIN

DBMS_OUTPUT.put_line('tr_emp_test 실행...');

END;

/

트리거가 생성되었습니다.

SQL> insert into emp (empno, ename, sal, deptno)

values (7677, '오자바커', 6000, 10);

1 개의 행이 만들어졌습니다.

SQL> alter trigger tr_emp_test enable;

트리거가 변경되었습니다.

SQL> insert into emp (empno, ename, sal, deptno)

values (7678, '오자바커', 3000, 30);

tr_emp_test 실행...

SQL> drop trigger tr_emp_test;

트리거가 삭제되었습니다.

SQL> drop trigger tr_test2_compound_trigger;

트리거가 삭제되었습니다.

댓글 없음:

댓글 쓰기

(C#교육동영상)C# ADO.NET 실습 ODP.NET/ODAC 설치 오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원

  (C#교육동영상)C# ADO.NET 실습  ODP.NET/ODAC 설치  오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원 https://www.youtube.com/watch?v=qIPU85yAlzc&list=PLxU-i...