✍TRIGGER(트리거)
: 테이블이나 뷰가 INSERT, UPDATE, DELETE 등의 DML문에 의해 변경될 경우(테이블 이벤트 발생 시)
자동으로(묵시적으로) 실행될 내용을 정의하여 저장하는 객체(PROCEDURE)
1. 트리거 종류
1) SQL문의 실행 시기에 따른 분류
- BEFORE TRIGGER : SQL문 실행 전 트리거 실행
- AFTER TRIGGER : SQL문 실행 후 트리거 실행
2) SQL문의 의해 영향을 받는 각 ROW에 따른 분류
- ROW TRIGGER : SQL문 각 ROW에 대해 한번씩 실행
트리거 생성 시 FOR EACH ROW 옵션 작성
- FOR EACH ROW 안에 아래 두개를 작성할 수 있는데
:OLD : 참조 전 열의 값 (INSERT: 입력 전 자료, UPDATE : 수정 전 자료, DELETE : 삭제할 자료)
:NEW : 참조 후 열의 값 (INSERT : 입력 할 자료, UPDATE : 수정 할 자료)
- STATMENT TRIGGER : SQL문에 대해 한번만 실행(DEFAULT TRIGGER)
참고 - 문장 트리거, 행 트리거
참고 1) 문장 트리거
트리거가 설정된 테이블에 트리거 이벤트가 발생하면 많은 행에 대해 변경 작업이 발생하더라도 오직 한번만 트리거를 발생시키는 방법
Insert, Update, Delete 한 번만 실행 된다. 컬럼값이 변화가 생길 때마다 스스로 알아서 실행 된다.
(FOR EACH ROW 옵션이 사용되지 않음)
예를 들어 "UPDETE emp SET 급여 = 급여 * 1.1;" 문장이 실행되면 여러 행에 대하여 자료가 변경 되더라도 한번만 트리거가 실행된다.
참고2) 행 트리거
조건을 만족하는 여러 개의 행에 대해 트리거를 반복적으로 여러 번 수행하는 방법으로 [FOR EACH ROW WHEN 조건]절 정의된다.
컬럼의 데이터 행이 변화가 오면 실행된다. 변경 후의 행은 OLD, NEW 사용하여 가저올 수 있다.
(FOR EACH ROW 옵션이 됨)
1. TRIGGER 생성 방법
[표현식]
CREATE [OR REPLACE] TRIGGER 트리거명
BEFORE | AFTER
INSERT | UPDATE | DELETE
ON 테이블명
[FOR EACH ROW] -- ROW TRIGGER 옵션
[WHEN 조건]
DECLARE -- 선언부
BEGIN -- 실행부
[EXCEPTION]
END;
/
📝 예제
👉 PRO_DATAIL 테이블에 데이터 INSERT할때마다
PRODUCT 테이블의 STOCK 컬럼 값을 자동으로 UPDATE하는 TRIGGER 구문 만들기 (입고, 출고) + 상품번호를 위한 SEQUENCE 필요
PRODUCT : 상품 정보 테이블 생성 / PRO_DATAIL : 상품 입출고 내역 테이블 생성
-- 상품 정보 테이블 생성
CREATE TABLE PRODUCT(
PCODE NUMBER PRIMARY KEY, --상품코드
PNAME VARCHAR2(200) NOT NULL, --상품명 ,꼭 이름이 들어가게 NOT NULL제약조건
BRAND VARCHAR2(60) NOT NULL, -- 제조사 브랜드명
PRICE NUMBER NOT NULL, --가격
STOCK NUMBER DEFAULT 0 -- 재고, 기본은 0부터 시작
);
--> Table PRODUCT이(가) 생성되었습니다.
-- 상품 입출고 내역 테이블
CREATE TABLE PRO_DETAIL(
DCODE NUMBER PRIMARY KEY, -- 각 행을 구분하는 식별자 역할 번호
PDATE DATE DEFAULT SYSDATE, -- 상품 입/출고일
AMOUNT NUMBER NOT NULL, -- 입/출고 개수
STATUS CHAR(6) CHECK(STATUS IN('입고', '출고') ), --입/출고 상태
-- 체크 제약조건 , 6바이트는 딱 두글자만 들어갈수 있고 STATUS에는 입고, 출고만 있을 수있다.
PCODE NUMBER REFERENCES PRODUCT -- 상품 코드( 상품 정보 테이블과 관계형성)
-- 두 테이블이 서로 관계가 있으므로 REFERENCES
);
-- 시퀀스 생성 //순차적 번호 자동 발생기 역할하는 객체
CREATE SEQUENCE SEQ_PCODE; -- 상품번호 생성 시퀀스
CREATE SEQUENCE SEQ_DCODE; -- 상품 입출고내역 구분 번호 생성 시퀀스
CREATE OR REPLACE TRIGGER STOCK_TRG
AFTER INSERT ON PRO_DETAIL -- PRO_DETAIL 테이블에 INSERT 된 후
FOR EACH ROW -- ROW TRIIGGER 옵션 : 행마다 TRIGGER를 적용한다.
BEGIN
IF (:NEW.STATUS = '입고')
THEN -- 입고
--PRODUCT 테이블에서 PCODE(상품번호)가 같은 행의 값을 증가
UPDATE PRODUCT SET --1. 테이블 업데이트 진행하는데
STOCK = STOCK + :NEW.AMOUNT --3. 기존 재고에 새로 입고된 물량을 추가
WHERE PCODE = :NEW.PCODE; --2. 만약 :NEW.PCODE와 PCODE가 같다면
ELSE -- 출고
UPDATE PRODUCT SET --1. 테이블 업데이트 진행하는데
STOCK = STOCK - :NEW.AMOUNT --3. 기존 재고에 새로 입고된 물량을 감소
WHERE PCODE = :NEW.PCODE; --2. 만약 :NEW.PCODE와 PCODE가 같다면
END IF;
END;
/
👉 :NEW
: 새로 INSERT된 행을 가리키는 바인드변수
참조 후 열의 값 (INSERT : 입력 할 자료, UPDATE : 수정 할 자료)
입고 & 출고 실행
1) 입고
--PCODE가 1인 상품 100개 입고
INSERT INTO PRO_DETAIL --입·출고니깐 DETAIL 테이블
VALUES( SEQ_DCODE.NEXTVAL, DEFAULT, 100, '입고', 1 );
-- SEQ_PCODE; -- 상품번호 생성 시퀀스, 출고일은 기본값인 오늘, 재고, 상태, 상품번호
INSERT INTO PRO_DETAIL --1번 1100개
VALUES( SEQ_DCODE.NEXTVAL, DEFAULT, 1000, '입고', 1 );
--> 수행 후 PRO_DETAIL, PRODUCT 테이블 확인
SELECT * FROM PRO_DETAIL; -- 창고관리자 보는 테이블
SELECT * FROM PRODUCT; -- 판매자가 보는 테이블 (재고 입고 확인 테이블)
--> 이런식으로 용도에 맞게 테이블 구분할 수 있다.
👉 .NEXTVAL:다음 시퀀스 번호를 얻어온다
-- 출고
INSERT INTO PRO_DETAIL
VALUES( SEQ_DCODE.NEXTVAL, DEFAULT, 900, '출고', 1);
SELECT * FROM PRO_DETAIL;
➡ 여기서 PRO_DETAIL 같이 구성한 테이블은 기록이 다 남기 때문에 유튜브 시청기록이나 조회수같은 곳에서 사용할 수 있는 테이블
그런데..! 트리거는 지정된 동작을 알아서 수행하는데 테이블을 수정하거나 데이터 수정 시 원치않게 동작하는 경우들이 있기때문에 유지보수가 힘들다.
응용) 재고가 -가 되는 경우 '재고보다 많이 출고할 수 없습니다' 문자 출력
조건을 ELSE -- 출고 뒤에 IF로 추가조건
CREATE OR REPLACE TRIGGER STOCK_TRG
AFTER INSERT ON PRO_DETAIL -- PRO_DETAIL 테이블에 INSERT 된 후
FOR EACH ROW -- ROW TRIIGGER 옵션 : 행마다 TRIGGER를 적용한다.
BEGIN
IF (:NEW.STATUS = '입고')
THEN -- 입고
--PRODUCT 테이블에서 PCODE(상품번호)가 같은 행의 값을 증가
UPDATE PRODUCT SET --1. 테이블 업데이트 진행하는데
STOCK = STOCK + :NEW.AMOUNT --3. 기존 재고에 새로 입고된 물량을 추가
WHERE PCODE = :NEW.PCODE; --2. 만약 :NEW.PCODE와 PCODE가 같다면
ELSE -- 출고
IF ( (SELECT STOCK
FROM PRODUCT
WHERE PCODE = :NEW.PCODE) - :NEW.AMOUNT >= 0) -- 기존 재고 - 새로 입고한 재고가 0이상이라면
THEN
UPDATE PRODUCT SET --1. 테이블 업데이트 진행하는데
STOCK = STOCK - :NEW.AMOUNT --3. 기존 재고에 새로 입고된 물량을 감소
WHERE PCODE = :NEW.PCODE; --2. 만약 :NEW.PCODE와 PCODE가 같다면
ELSE
DBMS_OUTPUT.PUT_LINE('재고보다 많이 출고할 수 없습니다');
END IF;
END;
/
'Backend > Oracle' 카테고리의 다른 글
[SQL] 계층형 쿼리 (0) | 2022.01.19 |
---|---|
DB 정리 (0) | 2021.09.30 |
[DB] PROCEDURE (0) | 2021.09.29 |
[DB] PL/SQL , (타입,레퍼런스)변수, 조건문, CASE문, 반복문, FOR , 예외처리 (0) | 2021.09.29 |
[DB] VIEW, SEQUENCE, INDEX (0) | 2021.09.29 |