본문 바로가기

Database/Oracle

오라클 트리거(TRIGGER)

//*****************************************
// 트리거(TRIGGER)
   TRIGGER란 DML 작업 즉, INSERT, DELETE, UPDATE 작업이 일어날 때 자동으로 실행되는 객체로 특히 이런 TRIGGER를 DML TRIGGER라 한다. TRIGGER는 데이터의 무결성 뿐만 아니라 다음과 같은 작업에도 사용된다.
   트리거 내에서는 COMMIT, ROLLBACK 문을 사용할 수 없다.

 -- 문장 트리거(문장당 한번만 실행)
    트리거가 설정된 테이블에 트리거 이벤트가 발생하면 많은 행에 대해 변경 작업이 발생하더라도 오직 한번만 트리거를 발생시키는 방법

 -- 행 트리거
    조건을 만족하는 여러 개의 행에 대해 트리거를 반복적으로 여러 번 수행하는 방법으로 [FOR EACH ROW WHEN 조건]절 정의된다.

 -- 형식
CREATE [OR REPLACE] TRIGGER 트리거명 [BEFORE | AFTER]
  이벤트-1 [OR 이벤트-2 OR 이벤트-3] ON 테이블명
  [FOR EACH ROW [WHEN TRIGGER 조건]]
  DECLARE
    선언문
  BEGIN
    PL/SQL 코드
  END;

 -- 이벤트
     INSERT, UPDATE, DELETE

    -- BEFORE : 구문을 실행하기 전에 트리거를 시작
    -- AFTER : 구문을 실행한 후에 트리거를 시작
    -- FOR EACH ROW : 행 트리거임을 알림
    -- WHEN 조건 : 사용자의 트리거 이벤트 중에 조건에 만족하는 데이터만 트리거 한다.
    -- REFERENCING : 영향 받는 행의 값을 참조
    -- :OLD : 참조 전 열의 값(INSERT : 입력 전 자료, UPDATE : 수정 전 자료, DELETE : 삭제할 자료)
    -- :NEW : 참조 후 열의 값(INSERT : 입력할 자료, UPDATE : 수정할 자료)

      ROW 트리거에서 컬럼의 실제 데이터 값을 제어하는데 사용하는 연산자는 :OLD와 :NEW 의사 레코드이다. 이 연산자와 함께 컬럼 명을 함께 기술한다. 예를 들어, 컬럼명이 sal이라고 하면, 변경전의 값은 :OLD.sal이고 변경 후의 값은 :NEW.sal 처럼 표기한다.

      문장 트리거에서는 :NEW, :OLD 를 참조 할 수 없다.

 -- 트리거 상태 확인
SQL>SELECT trigger_name, trigger_type, table_name FROM user_triggers;

 -- 트리거 삭제
DROP TRIGGER 트리거명;


//*****************************************
-- SYS 계정
-- 사용자에게 트리거를 만들 수 있는 권한 부여
GRANT CREATE TRIGGER TO 사용자명;

-- 사용자 계정
-- 부여된 권한 확인
SELECT * FROM USER_SYS_PRIVS;


//*****************************************
-- 문장 트리거
  트리거가 설정된 테이블에 트리거 이벤트가 발생하면 많은 행에 대해 변경 작업이 발생하더라도 오직 한번만 트리거를 발생시키는 방법

SELECT * FROM tab;

-- EXAM1 테이블이 존재하면 삭제
DROP TABLE EXAM1 PURGE;

-- 문장 트리거
CREATE TABLE EXAM1 (
    id NUMBER PRIMARY KEY
    ,name VARCHAR2(20)
);

CREATE TABLE EXAM2 (
    memo VARCHAR2(100)
    ,ilja    DATE DEFAULT SYSDATE
);

----------------------------------------------------
-- exam1 테이블에 추가, 수정, 삭제가되면 시간과 상태 저장 트리거
  -- 문장, AFTER 트리거
CREATE OR REPLACE TRIGGER trgExam
   AFTER DELETE OR INSERT OR UPDATE ON EXAM1
BEGIN
    IF INSERTING THEN
        INSERT INTO EXAM2(memo) VALUES ('추가');
    ELSIF UPDATING THEN
        INSERT INTO EXAM2(memo) VALUES ('수정');
    ELSIF DELETING THEN
        INSERT INTO EXAM2(memo) VALUES ('삭제');
    END IF;
END;

----------------------------------------------------
-- 트리거 확인
SELECT trigger_name, trigger_type, table_name
            FROM user_triggers;
SELECT TEXT FROM user_source;

INSERT INTO EXAM1(id, name) VALUES(1, 'aaa');
COMMIT;
SELECT * FROM EXAM1;
SELECT * FROM exam2;

-- 테이블의 프로시저, 함수, 패키지 등 상호 참조되는 관계 확인
 SELECT * FROM user_dependencies;

----------------------------------------------------
-- 날자 표현 형식 변경
ALTER SESSION SET NLS_DATE_LANGUAGE='KOREAN';

-- BEFORE 트리거(AFTER 트리거로 작성해도 동일한 결과 출력)
-- 일반적으로 BEFORE는 데이터를 검증할 때 사용됨)
CREATE OR REPLACE TRIGGER trgExam1
        BEFORE DELETE OR INSERT OR UPDATE ON EXAM1
BEGIN
    IF TO_CHAR(SYSDATE, 'DAY') IN ('토요일', '일요일')
         OR (TO_CHAR(SYSDATE, 'hh24') >= 12 AND
                TO_CHAR(SYSDATE, 'hh24') <= 13) THEN
                raise_application_error(-20007, '지금은 일못해');
    END IF;
END;

-- raise_application_error
    -- 표준화되지 않은 에러 코드와 에러 메시지를 리턴하기 위해 raise_application_error 프로시저 사용
     -- 코드값은 -20000~-20999사이의 수 사용   

INSERT INTO EXAM1(id, name) VALUES(5, 'bbb');
SELECT * FROM EXAM1;
SELECT * FROM exam2;

-- 위 트리거 수정
CREATE OR REPLACE TRIGGER trgExam1
        BEFORE DELETE OR INSERT OR UPDATE ON EXAM1
BEGIN
    IF TO_CHAR(SYSDATE, 'DAY') IN ('토요일', '일요일')
         OR TO_CHAR(SYSDATE, 'hh24') < 9 OR
                TO_CHAR(SYSDATE, 'hh24') > 18 THEN
                raise_application_error(-20007, '지금은 일못해');
    END IF;
END;

----------------------------------------------------
-- 테이블을 삭제하면 트리거도 자동적으로 지워진다.


//*****************************************
-- 행트리거
    조건을 만족하는 여러 개의 행에 대해 트리거를 반복적으로 여러 번 수행하는 방법으로 [FOR EACH ROW WHEN 조건]절 정의된다.
-- :NEW -> 참조후 열의 값
     -- INSERT에 의해 새로 추가된(할) 레코드
     -- UPDATE에 의해 수정된(할) 레코드
-- :OLD -> 참조전 열의 값
     -- UPDATE에 의해 수정되기 전 레코드
     -- DELETE에 의해 삭제된(할) 레코드

--  다음과 같은 방법을 이용하여 관련된 트리거는 하나의 트리거로 작성 할 수 있다.
CREATE OR REPLACE TRIGGER 트리거이름
AFTER[또는 BEFORE] DELETE OR INSERT OR UPDATE ON 테이블명
FOR EACH ROW
[
DECLARE
   변수 타입;
]
BEGIN
  IF INSERTING THEN
    -- 추가할 때
  ELSIF UPDATING THEN
    -- 수정할 때
  ELSIF DELETING THEN
    -- 삭제할 때
  END IF;
END;
/

----------------------------------------------------
CREATE TABLE demo1(
    id NUMBER,
    data VARCHAR2(20)
);

CREATE OR REPLACE TRIGGER demo_trigger
    BEFORE INSERT ON demo1 FOR EACH ROW
BEGIN
        SELECT TO_CHAR(SYSDATE, 'YYYY') INTO :new.id FROM dual;
END;
/
-- after 트리거는 :NEW를 수정 할 수 없다.

INSERT INTO demo1(id, data) VALUES(5, '우리');
COMMIT;

----------------------------------------------------
CREATE TABLE exama(
    hak VARCHAR2(20) PRIMARY KEY
    ,name VARCHAR2(20)
    ,kor NUMBER
    ,eng NUMBER
    ,mat NUMBER
);

CREATE TABLE examb(
    hak VARCHAR2(20) PRIMARY KEY
    ,tot NUMBER
    ,ave NUMBER(5, 1)
    ,CONSTRAINT fk_examb_hak FOREIGN KEY(hak)
                   REFERENCES exama(hak)
);

-- 행 트리거(AFTER) : 추가
CREATE OR REPLACE TRIGGER triInsExama
AFTER INSERT ON exama
FOR EACH ROW
DECLARE
    vtot NUMBER;
    vave NUMBER(5, 1);
BEGIN
    vtot := :NEW.kor + :NEW.eng + :NEW.mat;
    vave := ROUND(vTOt/3, 1);

    INSERT INTO examb(hak, tot, ave)
              VALUES(:NEW.hak, vtot, vave);
END;
/

INSERT INTO exama(hak, name, kor, eng, mat) VALUES
       ('1111', '홍길동', 80, 80, 80);
COMMIT;
SELECT * FROM exama;
SELECT * FROM examb;

-- 행 트리거(BEFORE) : 삭제
CREATE OR REPLACE TRIGGER triDelExama
BEFORE DELETE ON exama
FOR EACH ROW
BEGIN
    DELETE FROM examb WHERE hak = :OLD.hak;
END;
/

DELETE FROM exama WHERE hak = '1111';
COMMIT;
SELECT * FROM exama;
SELECT * FROM examb;

-- 행 트리거(AFTER) : 수정
CREATE OR REPLACE TRIGGER triUpdateExama
AFTER UPDATE ON exama
FOR EACH ROW
DECLARE
    vtot NUMBER;
    vave NUMBER(5, 1);
BEGIN
    vtot := :NEW.kor + :NEW.eng + :NEW.mat;
    vave := ROUND(vtot/3, 1);

    UPDATE examb SET tot=vtot, ave=vave
                 WHERE hak = :NEW.hak;  -- :OLD.hak
END;
/

'Database > Oracle' 카테고리의 다른 글

오라클 패키지  (0) 2014.11.21
오라클 예외처리  (0) 2014.11.21
오라클 커서와 동적SQL  (0) 2014.11.21
오라클 사용자 정의 함수(FUNCTION)  (0) 2014.11.21
오라클 프로시져(PROCEDURE)  (0) 2014.11.21