3 minute read

TRIGGER

  • TABLE에 INSERT/UPDATE/DELETE(DML) 구문에 의해 변경될 경우 자동으로 실행될 내용을 정의해 놓는 객체
    • TABLE에 이벤트 발생 시
  • SQL문의 실행 시기에 따라 분류
    • BEFORE TRIGGER : 해당 SQL 문장 실행 전 TRIGGER 실행
    • AFTER TRIGGER : 실행 후
  • SQL문에 의해 영향을 받는 행에 따른 분류
    • 문장 TRIGGER(STATEMENT TRIGGER) : 해당 SQL문에 대해 한 번만 TRIGGER 실행
    • 행 TRIGGER(ROW TRIGGER) : 해당 SQL문에 영향을 받는 행마다 TRIGGER 샐행
      • FOR EACH ROW 옵션 기술
CREATE OR REPLACE TRIGGER 트리거명
BEFORE/AFTER INSERT/UPDATE/DELETE ON 테이블명
[FOR EACH ROW]
[DECLARE
    선언부]
BEGIN
    실행부
[EXECPTION
    예외부]
END;
/

-- [] : 생략 가능

TRIGGER 생성

CREATE OR REPLACE TRIGGER TRG_01
AFTER UPDATE ON EMPLOYEE
BEGIN
    DBMS_OUTPUT.PUT_LINE('업데이트 실행');
END;
/

Alt text

트리거 생성 후 확인도 해봤다. 잘 생성이 되었다.

UPDATE EMPLOYEE
SET DEPT_CODE = 'D1'
WHERE DEPT_CODE =  'D9';

EMPLOYEE 테이블 내에 DEPT_CODE가 ‘D9’인 행을 모두 ‘D1’으로 변경했다.

CREATE OR REPLACE TRIGGER TRG_02
AFTER UPDATE ON EMPLOYEE
FOR EACH ROW -- 행 트리거
BEGIN
    DBMS_OUTPUT.PUT_LINE('변경 전 : ' || :OLD.DEPT_CODE ||', 변경 후 : ' || :NEW.DEPT_CODE);
END;
/

이번에는 FOR EACH ROW를 추가하여 행 트리거를 생성했다.
위에 TRG_01은 문장 트리거이다.

Alt text

EMPLOYEE 테이블의 행을 변경했을 때 TRI_01 / TRI_02 트리거가 각각 다르게 출력되는 것을 확인했다.
TRI_01 : 문장 트리거이기 때문에 5개의 행이 변경 되었어도 한 번만 실행된다.
TRI_02 : 행 트리거이기 때문에 5개의 행이 변경 되면 영향 받는 행의 갯수만큼(예제에서는 5번) 실행된다.


실습 예제

오늘 실습은 재고 관리 현황을 예로 해서 진행했다.
역시 상황 예시가 주어지고 실습을 하면 이해가 더 빠른 거 같다.

1) 상품 테이블 생성 PRODUCT
CREATE TABLE PRODUCT(
    PCODE NUMBER PRIMARY KEY, -- 상품 코드
    PNAME VARCHAR2(30),       -- 상품명
    BRAND VARCHAR2(30),       -- 브랜드명
    PRICE NUMBER,             -- 가격
    STOCK NUMBER DEFAULT 0    -- 재고
);
2) 상품코드 중복 방지 객체(SEQUENCE) 생성
CREATE SEQUENCE SEQ_PCODE;
3) 상품 데이터 INSERT
INSERT INTO PRODUCT VALUES(SEQ_PCODE.NEXTVAL, 'Z플립', '삼성', 1500000, DEFAULT);
INSERT INTO PRODUCT VALUES(SEQ_PCODE.NEXTVAL, '아이폰13', '애플', 1000000, DEFAULT);
INSERT INTO PRODUCT VALUES(SEQ_PCODE.NEXTVAL, '샤오미폰', '샤오미', 800000, DEFAULT);
4) 입출고 상세 이력 테이블 PRODETAIL & 시퀀스 생성
CREATE TABLE PRODETAIL(
    DCODE NUMBER PRIMARY KEY,  -- 입출력 이력 코드
    PDATE DATE,                -- 상품 입출고일
    AMOUNT NUMBER,             -- 수량
    STATUS VARCHAR2(10),       -- 상태 > 입출고
    PCODE NUMBER,              -- 상품 코드(외래키 지정, PRODUCT 테이블 참조)
    CHECK(STATUS IN ('입고', '출고')),
    FOREIGN KEY(PCODE) REFERENCES PRODUCT

    -- STATUS 컬럼 : 입고 OR 출고만 저장. CHECK 제약 조건 추가
);

CREATE SEQUENCE SEQ_DCODE;
5) 수업 시간 실습 예제
-- 1번 상품이 오늘 날짜로 10개 입고
INSERT INTO PRODETAIL VALUES (SEQ_DCODE.NEXTVAL, SYSDATE, 10, '입고', 1);
  • PRODETAIL에 10개를 추가해도 PRODUCT 테이블에는 반영되지 않는다. 당연.
    PRODUCT 테이블에는 추가하지 않았기 때문에!
UPDATE PRODUCT
SET STOCK = STOCK + 10
WHERE PCODE = 1;
  • 그래서 PRODUCT 테이블에도 1번 상품의 재고를 10개로 수정해줬다.

  • 두 개의 테이블의 정보가 연결되어 있지만, 재고가 들어왔을 때 두 개의 테이블을 모두 수정해줘야하는 일이 발생했다.
    테이블이 별로 없을 때는 가능하겠지만 그런 일은 극히 드물 것이고(실무에서) 가능하더라도 실수가 생길 수 있다.
    이럴 때 TRIGGER를 사용하면 된다.

재고 테이블(PRODETAIL)에 데이터 삽입 시 상품 테이블(PRODUCT)에 재고 수량을 업데이트하는 TRIGGER 생성

CREATE OR REPLACE TRIGGER TRG_PRO_STOCK
AFTER INSERT ON PRODETAIL
FOR EACH ROW -- 행 트리거 사용
BEGIN
    DBMS_OUTPUT.PUT_LINE(:NEW.STATUS || ' ' || :NEW.AMOUNT || ' ' || :NEW.PCODE);
END;
/

Alt text

트리거 생성 후 테이블을 수정했을 때 재고 테이블(PRODETAIL)을 수정하면
위와 같은 화면이 나온다.
차례대로 STATUS(상태) / AMOUNT(수량) / PCODE(상품코드)이다. 이걸 이용해서 입고, 출고가 되었을 때 각각 업데이트문을 실행시켜 준다.

CREATE OR REPLACE TRIGGER TRG_PRO_STOCK
AFTER INSERT ON PRODETAIL
FOR EACH ROW
BEGIN
    -- 상태 / 수량 / 상품코드
    DBMS_OUTPUT.PUT_LINE(:NEW.STATUS || ' ' || :NEW.AMOUNT || ' ' || :NEW.PCODE);
    
    -- 상품 입고
    IF (:NEW.STATUS = '입고') THEN
        UPDATE PRODUCT
        SET STOCK = STOCK + :NEW.AMOUNT
        WHERE PCODE = :NEW.PCODE;
    END IF;
    
    -- 상품 출고
    IF (:NEW.STATUS = '출고') THEN
        UPDATE PRODUCT
        SET STOCK = STOCK - :NEW.AMOUNT
        WHERE PCODE = :NEW.PCODE;
    END IF;
END;
/

와.. 이건 다시 봐도.. 트리거와 IF문.. 업데이트문의 조합. 웬욜.

-- 2번 상품이 오늘 날짜로 20개 입고
INSERT INTO PRODETAIL VALUES (SEQ_DCODE.NEXTVAL, SYSDATE, 20, '입고', 2);

트리거 생성 후 다시 상품을 입고시켰다.

Alt text

결과 : PRODETAIL 테이블의 수정이 발생 하면서 트리거가 실행 되었다.
트리거 실행 시, STATUS의 컬럼값이 ‘입고’일 경우 수량을 추가시켰기 때문에
PRODUCT(상품) 테이블의 내용도 출력된 것을 확인했다.


재밌고 신기하고 어렵다…


Categories:

Updated: