๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป/ORACLE

(29)[ORACLE] 12์ผ์ฐจ : PL/SQL - 5 (ํŠธ๋ฆฌ๊ฑฐ ๋ฐ ํŒจํ‚ค์ง€)

by ๋”ฐ๊ถˆ 2024. 3. 27.

 

 

ํŠธ๋ฆฌ๊ฑฐ๋ž€?
์Šคํ‚ค๋งˆ ๊ฐ์ฒด์˜ ์ผ์ข…์œผ๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๋ฏธ๋ฆฌ ์ •ํ•ด ๋†“์€ ํŠน์ • ์กฐ๊ฑด์ด ๋งŒ์กฑ๋˜๊ฑฐ๋‚˜
์–ด๋–ค ๋™์ž‘์ด ์ˆ˜ํ–‰๋˜๋ฉด ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ์ •์˜ํ•œ ๋™์ž‘.
ex. ํ…Œ์ด๋ธ”์— DML ๋ฌธ์žฅ์ด ์‹คํ–‰ ๋˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ DDL ๋ฌธ์žฅ์ด ์ˆ˜ํ–‰๋  ๋•Œ 
ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. 


ํŠธ๋ฆฌ๊ฑฐ(TRIGGER)์œ ํ˜•
DML ํŠธ๋ฆฌ๊ฑฐ INSERT, DELETE, UPDATE ์ž‘์—…์ด ์ผ์–ด๋‚  ๋•Œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฐ์ฒด๋กœ ์ด๋Ÿฐ TRIGGER๋ฅผ DML TRIGGER๋ผ ํ•œ๋‹ค. 
INSTEAD OF ํŠธ๋ฆฌ๊ฑฐ ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ๋ทฐ์— ์ •์˜๋œ ํŠธ๋ฆฌ๊ฑฐ
์‹œ์Šคํ…œ ํŠธ๋ฆฌ๊ฑฐ ์Šคํ‚ค๋งˆ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ •์˜๋œ ํŠธ๋ฆฌ๊ฑฐ 

 

 

ํŠธ๋ฆฌ๊ฑฐ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ

ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์‚ฌ์šฉ์ž๋Š” CREATE TRIGGER ๊ถŒํ•œ์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. 

-- ๊ด€๋ฆฌ์ž ๊ณ„์ • : sky ๊ณ„์ •์— ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ
GRANT CREATE TRIGGER TO sky;

-- sky ๊ณ„์ • : ์‹œ์Šคํ…œ ๊ถŒํ•œ ํ™•์ธ
SELECT * FROM user_sys_privs;

-- ํŠธ๋ฆฌ๊ฑฐ ํ™•์ธ
SELECT * FROM user_triggers; 

-- ํŠธ๋ฆฌ๊ฑฐ ์†Œ์Šค ํ™•์ธ    
SELECT * FROM user_source; 

-- ์˜์กด์„ฑ ํ™•์ธ
SELECT * FROM user_dependencies;

-- ํŠธ๋ฆฌ๊ฑฐ ์‚ญ์ œ
DROP TRIGGER testtrigger;

 

 

๋ฌธ์žฅ ํŠธ๋ฆฌ๊ฑฐ 

ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์„ค์ •๋œ ํ…Œ์ด๋ธ”์— ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋งŽ์€ ํ–‰์— ๋Œ€ํ•ด ๋ณ€๊ฒฝ ์ž‘์—…์ด ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ์˜ค์ง ํ•œ๋ฒˆ๋งŒ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ฐœ์ƒ ์‹œํ‚จ๋‹ค. 

-- test ํ…Œ์ด๋ธ”์— ์ง€์ •๋œ ์‹œ๊ฐ„์—๋งŒ dml์ด ๊ฐ€๋Šฅํ•œ ํŠธ๋ฆฌ๊ฑฐ ๋งŒ๋“ค๊ธฐ
CREATE OR REPLACE TRIGGER testtrigger
BEFORE INSERT OR UPDATE OR DELETE ON TEST
BEGIN
    if TO_CHAR(SYSDATE,'d') in (1,7) OR
    --(to_char(sysdate,'hh24') < 9 or to_char(sysdate,'hh24') > 18) then
    (TO_CHAR(SYSDATE,'hh24') >= 11 AND TO_CHAR(SYSDATE,'24') <= 12) THEN
    RAISE_APPLICATION_ERROR(-20001,'์ง€์ •๋œ ์‹œ๊ฐ„์—๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค');
    End If;
End;

 

 

ํ–‰ ํŠธ๋ฆฌ๊ฑฐ 

์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ–‰์— ๋Œ€ํ•ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ 'FOR EACH ROW [WHEN ์กฐ๊ฑด]'์ ˆ์„ ์ •์˜๋œ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์„ค์ •๋œ ํ…Œ์ด๋ธ”์— DELETE ์ด๋ฒคํŠธ๊ฐ€ ๋“ฑ๋ก๋œ ๊ฒฝ์šฐ, ํ•ด๋‹น ํ…Œ์ด๋ธ”์—์„œ DELETE ์ž‘์—…์ด 10๋ฒˆ ์ผ์–ด๋‚˜๋ฉด ํŠธ๋ฆฌ๊ฑฐ๋„ 10๋ฒˆ ์‹คํ–‰๋œ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ๊ฐ€ ํ–‰์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉด ํ–‰ ํŠธ๋ฆฌ๊ฑฐ๋Š” ํ•œ๋ฒˆ๋„ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. 

-- ํ–‰ ํŠธ๋ฆฌ๊ฑฐ
-- : DML ๋ฌธ์—์„œ ์กฐ๊ฑด๋งŒ์กฑํ•˜๋Š” ๋ชจ๋“  ํ–‰์— ๋Œ€ํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐ๋‚˜ ์ผ์–ด๋‚œ๋‹ค.
-- : ์˜ˆ๋ฅผ ๋“ค์–ด "DELETE FROM ํ…Œ์ด๋ธ”;" ๋ฌธ์žฅ์œผ๋กœ 5๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์‚ญ์ œ๋œ ๊ฒฝ์šฐ ํŠธ๋ฆฌ๊ฑฐ๋Š” 5๋ฒˆ ์‹คํ–‰ ๋œ๋‹ค.
-- : OLD ์™€ NEW ๋ ˆ์ฝ”๋“œ
  -- ํ–‰ ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  -- :OLD 
    UPDATE ์—์„œ๋Š” ์ˆ˜์ •์ „ ๋ ˆ์ฝ”๋“œ, DELETE ์—์„œ๋Š” ์‚ญ์ œํ•  ๋ ˆ์ฝ”๋“œ
  -- :NEW
    INSERT์—์„œ๋Š” ์ถ”๊ฐ€ํ•  ๋ ˆ์ฝ”๋“œ, UPDATE ์—์„œ๋Š” ์ˆ˜์ •ํ•  ๋ ˆ์ฝ”๋“œ


-- score1 ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด score2 ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ํŠธ๋ฆฌ๊ฑฐ ์ž‘์„ฑ
-- insert ํŠธ๋ฆฌ๊ฑฐ

CREATE OR REPLACE TRIGGER scoreinserttrigger
AFTER INSERT ON score1
FOR EACH ROW -- ํ–‰ ํŠธ๋ฆฌ๊ฑฐ
DECLARE
-- ํ•„์š”ํ•œ ๋ณ€์ˆ˜ ์„ ์–ธ
BEGIN 
INSERT INTO score2(hak, kor, eng, mat) VALUES(:NEW.hak, 
            fngrade(:NEW.kor), fngrade(:NEW.eng), fngrade(:NEW.mat)); 
            -- :new ํŠธ๋ฆฌ๊ฑฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์•ฝ์–ด
END;
/

 

 

ํŠธ๋ฆฌ๊ฑฐ ์ƒ์„ฑ

  • WHEN TRIGGER์กฐ๊ฑด : ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ ์ค‘์— ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ํŠธ๋ฆฌ๊ฑฐ ํ•œ๋‹ค.
  • OLD์™€ NEW์˜์‚ฌ ๋ ˆ์ฝ”๋“œ 
    • OLD์™€ NEW๋Š” ๋ฌธ์žฅ ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉด ํ–‰ ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค. OLD์™€ NEW๋Š” WHEN์ ˆ์—์„œ๋Š” OLD,NEW์ฒ˜๋Ÿผ ์•ž์— ์ฝœ๋ก (:)์„ ๋ถ™์ด์ง€ ์•Š์ง€๋งŒ ํŠธ๋ฆฌ๊ฑฐ ๋ณธ๋ฌธ์—์„œ๋Š” ์ฝœ๋ก (:)์„ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค. OLD๋Š” ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์ง€๋งŒ NEW๋Š” ๊ฐ€๋Šฅํ•˜๋‹ค. 
    • :OLD = UPDATE: ์ˆ˜์ •์ „ ์ž๋ฃŒ, DELETE : ์‚ญ์ œํ•  ์ž๋ฃŒ
    • :NEW = INSERT : ์ž…๋ ฅํ•  ์ž๋ฃŒ, UPDATE: ์ˆ˜์ •ํ•  ์ž๋ฃŒ 
--ํŠธ๋ฆฌ๊ฑฐ ์ƒ์„ฑ

CREATE[OR ROPLACE] TRIGGER ํŠธ๋ฆฌ๊ฑฐ์ด๋ฆ„ {BEFORE|AFTER}
์ด๋ฒคํŠธ ON ํ…Œ์ด๋ธ”์ด๋ฆ„
[FOR EACH ROW [WHEN TRIGGER์กฐ๊ฑด]]
DECLARE
๋ณ€์ˆ˜,์ƒ์ˆ˜๋“ฑ ์„ ์–ธ
BEGIN
์‹คํ–‰๊ตฌ๋ฌธ
END;

-- ํŠธ๋ฆฌ๊ฑฐ ์‹คํ–‰ ์‹œ๊ธฐ
-- BEFORE :ํ…Œ์ด๋ธ”์˜ DML ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ ์ „์— ํŠธ๋ฆฌ๊ฑฐ ๋ณธ๋ฌธ์ด ์‹คํ–‰
-- AFTER : ํ…Œ์ด๋ธ”์˜ DML ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ ์ „์— ํŠธ๋ฆฌ๊ฑฐ ๋ณธ๋ฌธ์ด ์‹คํ–‰
-- ์ด๋ฒคํŠธ : INSERT,UPDATE,DELETE

 

 

 


 

 

ํŒจํ‚ค์ง€๋ž€?
์˜ค๋ผํด์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์„œ๋กœ ๊ด€๋ จ ์žˆ๋Š” PL/SQL ํ”„๋กœ์‹œ์ €, ํ•จ์ˆ˜, ํƒ€์ž…๋“ฑ์„ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ฌถ์–ด ๋†“์€ ์ง‘ํ•ฉ
ํŒจํ‚ค์ง€๋Š” ์„ ์–ธ๋ถ€์™€ ๋ณธ๋ฌธ์œผ๋กœ ๋‚˜๋ˆˆ๋‹ค.
ํŒจํ‚ค์ง€ ๋‚ด์—์„œ๋Š” ํ”„๋กœ์‹œ์ €, ํ•จ์ˆ˜๋Š” ์˜ค๋ฒ„๋กœ๋”ฉ(์ค‘๋ณต ์ •์˜)์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


์˜ค๋ฒ„๋กœ๋”ฉ
๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐœ์ˆ˜๋‚˜ ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฉด ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ํ”„๋กœ์‹œ์ €๋‚˜ ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ์ •์˜ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์˜ค๋ฒ„๋กœ๋”ฉ์€ ํŒจํ‚ค์ง€ ๋‚ด์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

 

ํŒจํ‚ค์ง€ 

 

ํŒจํ‚ค์ง€ ์„ ์–ธ

์„ ์–ธ์ ˆ์€ ํŒจํ‚ค์ง€์— ํฌํ•จ๋  PL/SQL ํ”„๋กœ์‹œ์ €๋‚˜, ํ•จ์ˆ˜, ์ปค์„œ, ๋ณ€์ˆ˜, ์˜ˆ์™ธ ์ ˆ์„ ์„ ์–ธํ•œ๋‹ค. ํŒจํ‚ค์ง€ ์„ ์–ธ๋ถ€์—์„œ ์„ ์–ธํ•œ ๋ชจ๋“  ์š”์†Œ๋“ค์€ ํŒจํ‚ค์ง€ ์ „์ฒด์— ์ ์šฉ๋œ๋‹ค. 

 

CREATE OR REPLACE PACKAGE pEmp IS
        FUNCTION fnTax(pay IN NUMBER) RETURN NUMBER;
        PROCEDURE empList(pName VARCHAR2);
        PROCEDURE empList;
END pEmp;
/
--ํ•จ์ˆ˜์™€ ํ”„๋กœ์‹œ์ € ์ƒ์„ฑ 
--ํ”„๋กœ์‹œ์ € ์ด๋ฆ„์ด ๊ฐ™๋‹ค,์˜ค๋ฒ„๋กœ๋”ฉ ๊ฐ€๋Šฅ(๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ํ”„๋กœ์‹œ์ €๋กœ ์ฒ˜๋ฆฌํ•จ)

 

 

ํŒจํ‚ค์ง€ ์ƒ์„ฑ

ํŒจํ‚ค์ง€ ๋ณธ๋ฌธ์€ ํŒจํ‚ค์ง€์—์„œ ์„ ์–ธ๋œ ํ”„๋กœ์‹œ์ €๋‚˜ ํ•จ์ˆ˜์˜ ๋ชธ์ฒด๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

 

--ํŒจํ‚ค์ง€ ๋ชธ์ฒด ๊ตฌํ˜„


CREATE OR REPLACE PACKAGE BODY PEMP IS
    FUNCTION FNTAX(PAY IN NUMBER) --ํ•จ์ˆ˜
    RETURN NUMBER
    IS
         T NUMBER := 0;
    BEGIN
         IF PAY >= 3000000 THEN T := TRUNC(PAY*0.03,-1);
         ELSIF PAY >= 2000000 THEN T := TRUNC(PAY*0.02,-1);
         ELSE T :=0;
         END IF;
         RETURN T;
    END;
    
    PROCEDURE EMPLIST(PNAME VARCHAR2) --ํ”„๋กœ์‹œ์ €
    IS
        VNAME VARCHAR2(30);
        VSAL  NUMBER;
        CURSOR CUR_EMP IS
            SELECT NAME,SAL  
            FROM EMP WHERE INSTR(NAME,PNAME)>=1;
    BEGIN
        OPEN CUR_EMP;
        LOOP
            FETCH CUR_EMP INTO VNAME,VSAL;
            EXIT WHEN CUR_EMP%NOTFOUND;
            DBMS_OUTPUT.PUT_LINE(VNAME||':'||VSAL);
        END LOOP;
        CLOSE CUR_EMP;
    END;
    
    PROCEDURE EMPLIST --ํ”„๋กœ์‹œ์ € 
    IS
    BEGIN
        FOR REC IN (SELECT NAME,SAL+BONUS PAY,FNTAX(SAL+BONUS)TAX FROM EMP)LOOP
            DBMS_OUTPUT.PUT_LINE(REC.NAME||':'||REC.PAY||':'||REC.TAX);
        END LOOP;
    END;
END PEMP;

 

ํŒจํ‚ค์ง€๋‚ด์˜ ํ•จ์ˆ˜๋‚˜ ํ”„๋กœ์‹œ์ € ์‹คํ–‰์€ ํŒจํ‚ค์ง€ ๋ช… ๋‹ค์Œ์— ์ (.)์„ ์ฐ๊ณ  ํ”„๋กœ์‹œ์ €๋‚˜ ํ•จ์ˆ˜๋ช…์„ ์ ์–ด์ค€๋‹ค.

EXEC pEmp.empList('๊น€');
EXEC pEmp.empList;

 

ํŒจํ‚ค์ง€ ์‚ญ์ œ 

--์„ ์–ธ๋ถ€์™€ ๋ชธ์ฒด ์‚ญ์ œ
DROP PACKAGE ํŒจํ‚ค์ง€๋ช…;

--๋ชธ์ฒด ์‚ญ์ œ
DROP PACKAGE BOOY ํŒจํ‚ค์ง€๋ช…;