PL/SQL 익명 블록과 서브 프로그램의 차이
PL/SQL 블록에 이름을 지정하고 생성해서 저장해 두었다가 필요할 경우에 호출ㅇ해서 사용할 수 있도록 하는데 이를 서브프로그램 또는 프로그램 단위라 부른다.
대표 적인 유형으로 프로시저(PROCEDURE), 함수(FUNCTION), 패키지(PACKAGE), 트리거(TRIGGER) 가 있다
1. PROCEDURE (프로시저)
특정 작업을 처리하는 이름있는 PL/SQL BLOCK
프로시저 생성 - create procedure
프로시저 삭제 - drop procedure
프로시저 수정 - alter procedure
PROCEDURE 생성 문법 :
CREATE [OR REPLACE] PROCEDURE PROCEDURE_name
[( parameter1 [mode1] datatype1,
parameter2 [mode2] datatype2,
...)]
IS |AS
- OR REPLACE : 생성하고자 하는 PROCEDURE 가 기존에 동일 이름으로 존재할 경우, 기존의 내용을 현재 내용으로 수정하는 옵션, 이 옵션은 해당 이름의 PROCEDURE를 삭제한 후 다시 생성
- PROCEDURE_name : 생성하고자 하는 PROCEDURE 명으로 스키마 내에서는 유일하게 명명 되어야 한다
- parameter : PROCEDURE 를 실행할 때 호출 환경과 PROCEDURE 간 값을 주고 받을 때 사용되는 파라미터(매개변수)로 모드(IN,OUT,IN OUT) 에 따라 역할이 다르게 수행
PROCEDURE 생성시 선언부에 선언된 파라미터를 형식 파라미터
PROCEDURE 실행시 형식 파라미터에 실제 값이나 변수를 할당/대응 하는 파라미터를 실행 파라미터
- mode : 매개변수의 역할을 결정짓는 것
- IN 모드 : 사용자로부터 값을 입력받아 PROCEDURE 로 전달해 주는 역할을 하는 모드 (기본값으로 생략가능)
- OUT 모드 : PROCEDURE 에서 호출환경(SQL PLUS, 다른 프로시저 등)으로 값을 전달하는 역할
이 모드로 설정된 매개변수는 프로시저 내에서는 읽을 수 없으며, 값을 저장하기만 하는 지역변수처럼 사용
호출 환경에서는 이 매개변수로부터 값을 전달받기 위해 환경변수가 선언되어 있어야 함
- IN OUT 모드 : 설정된 매개변수는 호출환경과 프로시저 간에 값을 주고 받는 지역변수로 사용되며 읽기,쓰기가능
생성된 PROCEDURE 의 내용을 확인할 때는 USER_SOURCE 딕셔너리를 활용
실습 1. 부서번호가 20번 인 사람들의 job 을 'CLERK' 으로 변경하는 PROCEDURE
SQL> CREATE OR REPLACE PROCEDURE update_20
2 IS
3 BEGIN
4 UPDATE emp
5 SET job = 'CLERK'
6 WHERE deptno=20;
7 END ;
8 /
PROCEDURE created
SQL>EXEC update_20; --프로시저를 실행하려면 execute(줄여서 exec) 명령어로 프로시저 이름을 적고 실행
실습 2. 사번을 입력 받아 급여를 인상하는 PROCEDURE
SCOTT>SELECT empno, ename, sal FROM emp WHERE empno=7902 ;
EMPNO ENAME SAL
------ ------ ----
7902 FORD 3000 <- 변경전 SAL 값이 3000
SCOTT>CREATE OR REPLACE PROCEDURE up_sal
2 (vempno IN emp.empno%TYPE) -- 입력값을 저장할 변수 vempno 를 선언, IN 모드 기본값이라 생략가능
3 IS
4 BEGIN
5 UPDATE emp SET sal=5000
6 WHERE empno=vempno ;
7 END ;
8 /
PROCEDURE created
SCOTT>exec up_sal(7902) ; --PROCEDURE 를 실행할 때 수정할 사원번호를 함께 입력
EMPNO ENAME SAL
------ ------ ----
7902 FROD 5000 <- 변경후 급여가 500으로 바뀜
※ DB로 가서 데이터를 PL/SQL로 가져올 때 사용하는 변수는 3번째 줄과 4번째줄 사이 IS 와 BEGIN 사이에 입력하고,
2번 줄의 변수는 사용자로부터 데이터를 입력 받아서 PL/SQL 로 가져오는 역할을 하는 변수
실습 3. 사번을 입력 받아 그 사원의 이름과 급여를 출력하는 PROCEDURE
SCOTT>CREATE OR REPLACE PROCEDURE ename_sal
2 (vempno emp.empno%TYPE)
3 IS
4 vename emp.ename%TYPE ;
5 vsal emp.sal%TYPE ;
6 BEGIN
7 SELECT ename, sal
8 INTO vename, vsal
9 FROM emp
10 WHERE empno=vempno ;
11 DBMS_OUTPUT.PUT_LINE('사원명은 '||vename||' 입니다') ;
12 DBMS_OUTPUT.PUT_LINE('급여는 '||vsal||' 입니다') ;
13 END ;
14 /
SCOTT>exec ename_sal(7902) ;
-> 사원명은 FOR 입니다
급여는 5000 입니다
실습 4. OUT 모드 파라미터 사용 예
SCOTT>CREATE OR REPLACE PROCEDURE info_prf
2 (v_profno IN professor.profno%TYPE,
3 v_name OUT professor.name%TYPE, --이름값을 저장할 변수
4 v_pay OUT professor.pay%TYPE ) --급여를 저장할 변수
5 IS
6 BEGIN
7 SELECT name, pay INTO v_name, v_pay
8 FROM professor
9 WHERE profno = v_profno ;
10 END info_prof ;
11 /
위에서 작성한 PROCEDURE 를 호출해서 값을 가져오는 익명 블록 PL/SQL 문을 작성
SCOTT>DECLARE
2 v_name professor.name%TYPE ;
3 v_pay professor.pay%TYPE ;
4 BEGIN
5 info_prof(1001,v_name,v_pay) ;
6 DBMS_OUTPUT.PUT_LINE(v_name||' 교수의 급여는 '||v_pay||'입니다') ;
7 END ;
8 /
-> 조인형 교수의 급여는 550 입니다
위 예에서 5번 줄을 보면 프로시저를 호출 할 때 값을 주는 것을 알 수 있습니다.
또는 아래와 같이 DBMS_OUTPUT.PUT_LINE 문장으로 사용도 가능
SCOTT>DECLARE
2 v_name professor.name%TYPE ;
3 v_pay professor.pay%TYPE ;
4 BEGIN
5 info_prof(1001,v_name,v_pay) ;
6 DBMS_OUTPUT.PUT_LINE('이 름:'||v_name) ;
7 DBMS_OUTPUT.PUT_LINE('급 여:'||v_pay) ;
8 END ;
9 /
-> 이 름 : 조인형
급 여 : 550
또 다른 방법으로는 별도의 변수를 선언해서 값을 수행해서 받은 후 출력할 수 도 있습니다.
SCOTT>VARIABLE name VARCHAR2(10)
SCOTT>VARIABLE pay NUMBER
SCOTT>EXEC info_prof(1001, :name, :pay) ;
SCOTT>PRINT name pay
NAME
-----------
조인형
PAY
-----------
550
2. FUNCTION (함수)
함수 생성 : CREATE FUNCTION
함수 삭제 : DROP FUNCTION
함수 수정 : ALTER FUNCTION
에러 발생시 : SHOW ERRORS 확인
함수 예제 1. 부서번호를 입력 받아 최고 급여액을 출력하는 함수
SQL>CREATE OR REPLACE FUNCTION f_max_sal
2 (v_deptno emp.deptno%TYPE)
3 RETURN NUMBER
4 IS
5 max_sal emp.sal%TYPE ;
6 BEGIN
7 SELECT max(sal) INTO max_sal
8 FROM emp
9 WHERE deptno = v_deptno ;
10 RETURN max_sal ; -- 이부분의 데이터 형이 위 3번 줄의 형과 같아야 함
11 END ;
12 /
SQL>SELECT f_max_sal(10) FROM dual ;
F_MAX_SAL(10)
-------------
5000
SQL>SELECT f_max_sal(20) FROM dual ;
F_MAX_SAL(20)
-------------
3000
함수 예제 2. 부서번호를 입력 받은 후 해당 부서의 인원수를 구해주는 함수
SQL>CREATE OR REPLACE FUNCTION count_mem
2 (v_deptno NUMBER)
3 RETURN NUMBER
4 IS
5 total_count NUMBER
6 BEGIN
7 SELECT count(*) INTO total_count
8 FROM emp
9 WHERE deptno = v_deptno ;
10 RETURN total_count ; -- 이 부분의 데이터 형이 위 3번 줄 데이터 형과 같아야 함
11 END;
12 /
SQL> SELECT DISTINCT deptno, COUNT_MEM(deptno)
2 FROM emp ;
DEPTNO COUNT_MEM(DEPTNO)
------- -------------------
30 6
20 5
10 3
함수 예제 3. 부서번호를 입력 받아 부서별로 평균 급여를 구해주는 함수
SQL>CREATE OR REPLACE FUNCTION avg_sal
2 (v_deptno emp.deptno%TYPE)
3 RETURN NUMBER
4 IS
5 avg_sal NUMBER ;
6 BEGIN
7 SELECT ROUND(AVG(sal),2) INTO avg_sal
8 FROM emp
9 WHERE deptno = v_deptno ;
10 RETURN avg_sal ;
11 END ;
12 /
SQL> SELECT DISTINCT deptno, AVG_SAL(deptno)
2 FROM emp ;
DEPTNO AVG_SAL(DEPTNO)
------- ----------------
30 1566.67
10 2916.67
20 2175
함수 예제 4. 사원번호를 입력 받아 해당 사원의 부서명을 알려주는 함수
SQL>CREATE OR REPLACE FUNCTION f_dname
2 (v_empno IN emp.empno%TYPE)
3 RETURN varchar2
4 IS
5 v_dname dept.dname%TYPE ;
6 BEGIN
7 SELECT dname INTO v_dname
8 FROM dept
9 WHERE deptno = ( SELECT deptno
FROM emp
WHERE empno = v_empno) ;
10 RETURN v_dname ;
11 END ;
12 /
SCOTT> SELECT ename, deptno, F_DNAME(empno) "DNAME"
2 FROM emp ;
ENAME DEPTNO DNAME
------ ------- ------------
홍길동 10 ACCOUNTING
일지매 30 SALES
SMITH 20 RESEARCH
ALLEN 30 SALES
.......
함수 예제 5. 생성된 함수 조회하기
SCOTT>SELECT text
2 FROM user_source
3 WHERE type='FUNCTION'
4 AND name = 'F_MAX_SAL' ;
TEXT
-------------------------------------------
function f_max_sal
(s_deptno emp.deptno%TYPE)
return NUMBER
IS
max_sal emp.sal%TYPE ;
begin
select max(sal) into max_sal
from emp
where deptno=s_deptno ;
return max_sal ;
end ;
3. ORACLE PACKAGE (패키지)
연관성이 높은 함수나 PROCEDURE 를 하나의 그룹으로 묶어서 관리하고 사용하는 개념
PACKAGE 는 PACKAGE 선언부(Spec)와 PACKAGE 몸체부(body) 로 구성
- PACKAGE 선언부 : 해당 패키지에 사용될 함수나 프로시저, 변수 등에 대한 정의를 선언
- PACKAGE 몸체부 : 선언부에서 선언된 함수나 ㅡㅍ로시저 등이 실제 CODE로 구현되는 부분
만약 생성된 PACKAGE의 선언부가 변경되었다면 무조건 PACKAGE 몸체부는 재 생성해야 하며, 패키지를 참조(호출)하는 서브 프로그램들도 재 번역(recompile)해야한다. 반대로 패키지 몸체부만 변경되는 경우라면 몸체부만 재생성하면 된다.
1. 패키지 실행 하기
생성된 패키지 오브젝트에 대한 실행 권한을 가진 사용자만이 패키지를 호출하여 실행 할 수 있다
2. 패키지 삭제
패키지 선언부와 몸체부 모두 삭제 : DROP PACKAGE PACKAGE_name ;
패키지 몸체부만 삭제 : DROP PACKAGE BODY PACKAGE_name ;
사용 예 1. Emp table 에서 총 급여 합계와 평균 급여를 구하는 emp_sal_mgr PACKAGE 입니다.
패키지 선언부
SQL>CREATE OR REPLACE PACKAGE emp_sal_mgr
2 AS
3 PROCEDURE emp_sal_sum ;
4 PROCEDURE emp_sal_avg ;
5 END emp_sal_mgr ;
6 /
패키지 몸체부
SQL>CREATE OR REPLACE PACKAGE BODY emp_sal_mgr
2 AS
3 PROCEDURE emp_sal_sum
4 IS
5 CURSOR emp_total_sum IS
6 SELECT COUNT(*), SUM(NVL(sal,0))
7 FROM emp ;
8 total_num NUMBER ;
9 total_sum NUMBER ;
10 BEGIN
11 OPEN emp_total_sum ;
12 FETCH emp_total_sum INTO total_num, total_sum ;
13 DBMS_OUTPUT.PUT_LINE('총인원수:'||total_num||', 급여합계: '||total_sum) ;
14 CLOSE emp_total_sum ;
15 END emp_sal_sum ; --emp_sum 합계 구하는 PROCEDURE 끝
16 PROCEDURE emp_sal_avg --emp_avg 평균 구하는 PROCEDURE 시작
17 IS
18 CURSOR emp_total_avg IS
19 SELECT COUNT(*),AVG(NVL(sal,0))
20 FROM emp ;
21 total_num NUMBER ;
22 total_avg NUMBER ;
23 BEGIN
24 OPEN emp_total_avg ;
25 FETCH emp_total_avg INTO total_num, total_avg ;
26 DBMS_OUTPUT.PUT_LINE('총인원수:'||total_avg||', 급여합계: '||total_avg) ;
27 CLOSE emp_total_avg ;
28 END emp_sal_avg ; --평균 구하는 PROCEDURE 끝
29 END emp_sal_mgr ; --PACKAGE 끝
30 /
생성된 패키지 실행
SQL>SET SERVEROUTPUT ON
SQL>EXEC emp_sal_mgr.emp_sal_sum ; --패키지이름.프로시저 이름으로 실행
-> 총인원수 : 14, 급여합계 : 29025
SQL>EXEC emp_sal_mgr.emp_sal_avg ;
-> 총 인원수 : 14, 급여평균 : 2073.214287................
위 패키지 실행결과가 맞는지 sql을 직접 수행해서 검증
SQL>SELECT COUNT(*), SUM(NVL(sal,0)) FROM emp;
COUNT(*) SUM(NVL(SAL,0))
-------- ---------------
14 29025
사용 예2. member 테이블에 등록되어 있는 회원들의 성별과 아이디 검색과 비밀번호를 검색해주는 패키지
사용자 정보가 들어있는 member 테이블을 사용하여 회원관리를 하는 PL/SQL 패키지를 생성
이 패키지는 아래와 같은 프로시저로 구성
- 사용자 이름을 입력 받은 후 남자인지 여자인지를 구분하는 pro_gender 프로시저
- 사용자 이름과 주민번호를 입력 받아 회원의 아이디를 찾아주는 pro_find_id 프로시저
- 사용자 아이디와 연상단어를 입력 받아 회원의 비밀번호를 알려주는 pro_fin_pw 프로시저
1. 패키지 선언부를 생성
SCOTT>CREATE OR REPLACE PACKAGE pkg_member
2 IS
3 PROCEDURE pro_gender
4 (v_name IN member.name%TYPE) ;
5 PROCEDURE pro_find_id
6 (v_name IN member.name%TYPE ,
7 v_jumin2 IN member.jumin%TYPE) ;
8 PROCEDURE pro_find_pw
9 (v_id IN member.id%TYPE,
10 v_an IN member.an_key_dap%TYPE ) ;
11 END pkg_member ;
12 /
2. 패키지 몸체부를 생성
SCOTT>CREATE OR REPLACE PACKAGE BODY pkg_member
2 AS
3 PROCEDURE pro_gender(v_name IN member.name%TYPE) --성별 조회하는 프로시저,
4 IS
5 v_name2 member.name%TYPE ;
6 v_gender CHAR(4) ;
7 v_count NUMBER := 0 ;
8 exception_noname EXCEPTION ;
9 BEGIN
10 SELECT count(*) INTO v_count
11 FROM member
12 WHERE name = v_name ;
13 IF v_count = 0 THEN
14 RAISE exception_noname ;
15 ELSE
16 SELECT name, CASE WHEN SUBSTR(jumin,7,1) IN (1,3) THEN '남자' ELSE '여자' END
17 INTO v_name2, v_gender
18 FROM member
19 WHERE name = v_name ;
20 DBMS_OUTPUT.PUT_LINE(v_name2||' 님의 성별은 '||v_gender||' 입니다') ;
21 END IF ;
22 EXCEPTION
23 WHEN exception_noname
24 THEN RAISE_APPLICATION_ERROR(-20001,'그런 이름은 없습니다!') ;
25 END pro_gender ; --성별 조회 PROCEDURE 종료
26 PROCEDURE pro_find_id --이름,주민번호 입력받아 아이디를 검색하는 프로시저
27 (v_name IN member.name%TYPE ,
28 v_jumion2 IN member.jumin%TYPE )
29 IS
30 v_count NUMBER := 0 ;
31 v_count2 NUMBER := 0 ;
32 v_name2 member.name%TYPE ;
33 v_id2 member.id%TYPE ;
34 exception_noname EXCEPTION ;
35 excetpion_nojumin EXCEPTION ;
36 BEGIN
37 SELECT count(*) INTO v_count
38 FROM member
39 WHERE name = v_name ;
40 IF v_count = 0 THEN
41 RAISE exception_noname ; --이름이 없을 경우 에러를 발생시킴
42 ELSE
43 SELECT count(*) INTO v_count2
44 FROM member
45 WHERE jumin = v_jumin2 ;
46 IF v_count2 = 0 THEN
47 RAISE exception_nojumin ; -- 주민번호가 없을 경우 에러를 발생시킴
48 ELSE
49 SELECT name, id INTO v_name2, v_id2
50 FROM member
51 WHERE name = v_name ;
52 END IF ;
53 END IF ;
54 DBMS_OUTPUT.PUT_LINE(v_name2||' 님의 아이디는 '||v_id2||'입니다') ;
55 EXCEPTION
56 WHEN exception_noname
57 THEN RAISE_APPLICATION_ERROR(-20001,'입력하신 이름은 없습니다!') ;
58 WHEN exception_nojumin
59 THEN RAISE_APPLICATION_ERROR(-20002,'입력하신 주민번호는 없습니다!') ;
60 END pro_find_id ; --아이디를 찾는 프로시저를 종료
61 PROCEDURE pro_find_pw --아이디와 연관단어를 입력하여 비번을 찾아내는 프로시저
62 (v_id IN member.id%TYPE ,
63 v_an IN member.an_key_dap%TYPE )
64 IS
65 v_count NUMBER := 0 ;
66 v_id2 member.id%TYPE ;
67 v_an_dap member.an_key_dap%TYPE ;
68 v_pw member.passwd%TYPE ;
69 exception_noid EXCEPTION ;
70 exception_noan EXCEPTION ;
71 BEGIN
72 SELECT count(*) INTO v_count
73 FROM member
74 WHERE id = v_id ;
75 IF v_count = 0 THEN
76 RAISE exception_noid ; -- 아이디가 없으면 에러를 발생시킴
77 ELSE
78 SELECT an_key_dap INTO v_an_dap
79 FROM member
80 WHERE id = v_id ;
81 IF v_an_dap = v_an THEN
82 SELECT id, passwd INTO v_id2, v_pw
83 FROM member
84 WHERE id = v_id ;
85 ELSE RAISE exception_noan ;
86 END IF ;
87 END IF ;
88 DBMS_OUTPUT.PUT_LINE('입력하신 '||v_id||' 의 비밀번호는 '||v_pw||' 입니다!') ;
89 EXCEPTION
90 WHEN exception_noid
91 THEN RAISE_APPLICATION_ERROR (-20003,'입력하신 아이디는 없습니다!') ;
92 WHEN exception_noan
93 THEN RAISE_APPLICATION_ERROR (-20003,'입력하신 연상단어가 틀립니다!') ;
94 END pro_find_pw ; -- 프로시저를 종료
95 END pkg_member ; -- 패키지 종료
96 /
- pro_gender PROCEDURE 테스트
SCOTT>EXEC pkg_member.pro_gender('홍길동') ;
-> 홍길동 님의 성별은 남자 입니다
SCOTT>EXEC pkg_member.pro_gender('유관순') ;
-> 유관순 님의 성별은 여자 입니다
- pro_find_id PROCEDURE 테스트
이름과 주민번호를 입력하면 아이디를 검색해주는 기능
SCOTT>EXEC pkg_member.pro_find_id('홍길동',7510231234567') ;
-> 홍길동님의 아이디는 simson 입니다
- pro_find_pw PROCEDURE 테스트
SCOTT>EXEC pkg_member.pro_find_pw('simson','홍길동') ;
-> 입력하신 simson 의 비밀번호는 a1234 입니다
4. TRIGGER (트리거)
테이블, 뷰, 스키마 또는 데이터베이스에 관련된 PL/SQL블록(또는 프로시저)으로 관련된 특정 사건(EVENT)이 발생될 때마다 묵시적(자동) 으로 해당 PL/SQL TRIGGER 블록이 실행됨
간단한 예로 테이블에 상품이 입고되면(EVENT 발생) 재고 테이블에 자동으로 재고가 증가하게 만드는것
1) 주요 트리거 유형
(1) 단순 DML TRIGGER
- BEFORE TRIGGER
테이블에서 DML 이벤트를 TRIGGER 하기 전에 TRIGGER 본문을 실행
즉 어떤 작업을 하기전에 TRIGGER를 먼저 수행 한 후 작업을 하는 경우
- AFTER TRIGGER
테이블에서 DML 이벤트를 TRIGGER 한 후에 TRIGGER 본문을 실행
- INSTEAD OF TRIGGER
TRIGGER 문 대신 TRIGGER 본문을 실행, 다른 방법으로는 수정이 불가능한 뷰에 사용
DML TRIGGER
- 문장 TRIGGER : 대상이 모든 행으로 영향을 받는 행이 없더라도 TRIGGER가 한 번은 실행 됨
예를들어 특정 테이블에 데이터를 입력할 수 있는 시간을 지정하는 경우 어떤 데이터가 들어오던지 간에 TRIGGER 를 적용
- 행 TRIGGER : 특정 행이 TRIGGER 이벤트의 영향을 받을 경우 해당 TRIGGER가 실행되고 영향을 받는 행이 없을 경우 TRIGGER 가 실행되지 않는다.
얘를들어 제품번호가 100번인 제품만 입력안되게 막고 싶을 경우 다른 행은 TRIGGER 와 상관없지만 100번 제품은 TRIGGER 가 적용되어 입력이 안됨
행 TRIGGER가 실행될 때 PL/SQL 런타임 엔진은 두개의 데이터 구조를 생성하고 채움
- OLD : TRIGGER 가 처리한 레코드의 원래 값(기존값) 을 저장
- NEW : 새로 입력되거나 변경되는 값을 의미
(2) 혼합 TRIGGER (11g 부터 추가)
여러가지 TRIGGER 를 하나로 만든 것으로 PL/SQL 의 패키지와 비슷한 개념
혼합 TRIGGER 가 주로 사용되는 시점
- 실행되는 문장 앞에
- 실행되는 문장이 영향을 주는 각 행 앞에
- 실행되는 문장이 영향을 주는 각 행 뒤에
- 실해오디는 문장 뒤에
혼합 TRIGGER 생성시 주의사항
- 혼합 TRIGGER 는 DML TRIGGER여야 하며 테이블이나 뷰에 정의해야 한다
- 혼합 TRIGGER의 본문은 PL/SQL 에서 작성한 혼합 TRIGGER 블록이어야 한다
- 혼합 TRIGGER 본문에는 초기화 블록이 포함될 수 없으므로 예외 섹션이 있을수 없다
- 한 섹션에서 발생하는 예외는 해당 섹션에서 처리되어야 한다
- :OLD 및 :NEW 는 선언, BEFORE STATEMENT 또는 AFTER STATEMENT 섹션에 나타날수 없다
- BEFORE EACH ROW 섹션만 :NEW 값을 변경할 수 있다
- FOLLOWS 절을 사용하지 않으면 혼합 TRIGGER 의 실행 순서가 일정하지 않는다
2) TRIGGERR 구조
트리거는 트리거가 실행되는 시점(Timing), 트리거를 실행시키는 사건(Event), 트리거와 관련된 테이블/뷰/스키마/데이터베이스 그리고 트리거 몸체부(body)로 구성
3) TRIGGER 관리
(1) 활성화/비활성화 하기
SQL>ALTER TRIGGER TRIGGER_name DISABLE | ENABLE ;
(2) 특정 테이블에 속한 TRIGGER의 활성화/비활성화
SQL>ALTER TABLE table_name DISABLE | ENABLE ALL TRIGGERS ;
(3) TRIGGER 수정 후 다시 컴파일
SQL>ALTER TRIGGER tirgger_name COMPILE ;
(4) TRIGGER 삭제
SQL>DROP TRIGGER trigger_name ;
(5) TRIGGER 관련 권한
※ TRIGGER 를 생성, 변경 및 삭제할 수 있는 권한
- GRANT CREATE TRIGGER TO SCOTT ;
- GRANT ALTER ANY TRIGGER TO SCOTT ;
- GRANT DROP ANY TRIGGER TO SCOTT ;
※ 데이터베이스에서 TRIGGER를 생성할 수 있는 권한
- GRANT ADMIN IS TER DATABASE TRIGGER TO SCOTT ;
※ EXCUTE 권한 (TRIGGER 가 실행하는 스키마에 포함되지 않은 객체를 참조하는 경우)
4) TRIGGER 예제
(실습을 하기전 scott 사용자에게 create trigger 권한을 할당)
SYS>GRANT create trigger TO scott ;
예 1) 테이블에 데이터를 입력할 수 있는 시간 지정하기
(테이블 전체가 대상이므로 문장 레벨 TRIGGER 사용)
테스트를 위해 연습용 테이블 t_order 테이블 생성
SCOTT>CREATE TABLE t_order_tab
2 ( no NUMBER ,
3 ord_code VARCHAR2(10),
4 ord_date DATE ) ;
데이터를 입력할 때 입력시간이 18:40 분에서 18:50 분일 경우만 입력을 허용하고 그 외는 에러발생 트리거 생성
SCOTT>CREATE OR REPLACE TRIGGER t_order
2 BEFORE INSERT ON t_order_tab
3 BEGIN
4 IF(TO_CHAR(SYSDATE,'HH24:MI') NOT BETWEEN '18:40' AND '18:50') THEN
5 RAISE_APPLICATION_ERROR(-20100,'허용시간 아닙니다') ;
6 END IF ;
7 END ;
8 /
18:40 ~ 18:50 에 입력 할 경우
SCOTT>INSERT INTO t_order_tab
2 VALUES(1,'C100',SYSDATE) ;
-> 1 row created -- 정상적으로 입력됨
18:40 ~ 18:50 이외의 시간에 입력 할 경우
SCOTT>INSERT INTO t_order_tab
2 VALUES(2,'C200',SYSDATE) ;
-> ERROR at line 1:
ORA-20100: 허용시간 아닙니다 -- 의도하던 에러 발생
예 2) 테이블에 입력될 데이터 값을 지정하고 그 값 이외에는 에러를 발생시키는 TRIGGER 를 생성
SCOTT>CREATE OR REPLACE TRIGGER t_order2
2 BEFORE INSERT ON t_order_tab
3 FOR EACH ROW --행 레벨 TRIGGER
4 BEGIN
5 IF(:NEW.ord_code) NOT IN ('C100') THEN --:NEW 새로들어오는 데이터
6 RAISE_APLICATION_ERROR(-20200,'제품코드가 틀립니다!') ;
7 END IF ;
8 END ;
9 /
신규 내용을 입력하는데 앞에서 생성한 문장레벨 TRIGGER로 인해 입력이 안됨
따라서 앞의 실습에서 만든 TRIGGER 삭제
SCOTT>DROP TRIGGER t_order ;
올바른 제품코드 입력
SCOTT>INSERT INTO t_order_tab
2 VALUES(2,'C100',SYSDATE) ;
-> 1 row created - 정상입력
틀린 제품코드(C200) 입력
SCOTT>INSERT INTO t_order_tab
2 VALUES(3,'C200',SYSDATE) ;
-> ERROR at line 1:
ORA-20200 : 제품코드가 틀립니다! - 의도하던 오류 발생
예 3) TRIGGER 의 작동 조건을 WHEN 절로 더 구체적으로 지정
ORD_CODE 가 'C500' 인 제품에 대해서만 19:30 부터 19:35 까지 입력을 허용하는 TRIGGER
다른 제품코드느 시간 관계없이 정상적으로 입력 가능
SCOTT>CREATE OR REPLACE TRIGGER t_order3
2 BEFORE INSERT ON t_order_tab
3 FOR EACH ROW
4 WHEN (NEW.ord_code ='C500') <-- WHEN 절에는 NEW 앞에 콜론 기호(:) 삭제
5 BEGIN
6 IF(TO_CHAR(SYSDATE,'HH24:MI')NOT BETWEEN '19:30 AND '19:35')THEN
7 RAISE_APPLICATION_ERROR(-20300,'C500 제품의 입력허용시간이 아닙니다!') ;
8 END IF
9 END ;
10 /
예 4) 특정 테이블에 입력할 수 있는 계정을 지정하기
(테이블 자체가 대상이므로 문장 TRIGGER 를 사용)
실습을 위해 새로운 테이블을 생성
SCOTT>CREATE TABLE t_test1(no NUMBER);
SCOTT>CREATE TRIGGER t_usercheck
2 BEFORE INSERT OR UPDATE OR DELETE
3 ON t_test1
4 BEGIN
5 IF USER NOT IN ('SCOTT','HR') THEN
6 RAISE_APPLICATION_ERROR(-20001,'허락된 계정이 아닙니다!!') ;
7 END IF ;
8 END ;
9 /
테스트를 위해 새로운 사용자 계정 USER1을 생성하고 필요한 권한을 할당
SCOTT> conn / as sysdba
SYS>CREATE USER user1 IDENTIFIED BY user1
2 DEFAULT TABLESPACE users
3 TEMPORARY TABLESPACE temp ;
SYS>GRANT connect, resource TO user1 ;
SYS>GRANT INSERT ON scott.t_test1 TO user1 ;
SCOTT>CONN user1/user1
USER1>INSERT INTO scott.t_test1 VALUES(1) ;
-> ERROR at line 1:
ORA-20001 : 허락된 계정이 아닙니다!!
예 5. 기존 테이블(t_test1) 에 데이터가 업데이트 될 때 기존 내용을 백업테이블(t_test2)으로 옮겨놓는 TRIGGER 를 생성. 삭제되는 특정 행이 TRIGGER의 대상이므로 행 레벨 TRIGGER를 사용
SCOTT>CREATE TABLE t_test1
2 (no NUMBER, name VARCHAR2(10)) ;
SCOTT>CREATE TABLE t_test2
2 AS SELECT * FROM t_test1 ;
SCOTT>INSERT INTO t_test1 VALUES (1,'AAA') ;
SCOTT>INSERT INTO t_test1 VALUES (2,'BBB') ;
SCOTT>COMMIT ;
SCOTT>CREATE OR REPLACE TRIGGER t_move
2 BEFORE UPDATE ON t_test1
3 FOR EACH ROW
4 BEGIN
5 INSERT INTO t_test2 VALUES (:OLD,no , :OLD.name) ;
6 END ;
7 /
위 예에서 5번 라인에 :OLD.no , :OLD,name 은 update 되면서 이전 데이터를 의미
SCOTT>SELECT * FROM t_test1 ;
NO NAME
--- -----
1 AAA
2 BBB
SCOTT>SELECT * FROM t_test2 ;
no rows selected
SCOTT>UPDATE t_test1
2 SET no=2
3 WHERE name='AAA' ;
1 row updated.
SCOTT>SELECT * FROM t_test2 ;
NO NAME
--- ------
1 AAA
'오라클 > PL/SQL' 카테고리의 다른 글
PL/SQL 예외처리 (0) | 2014.10.16 |
---|---|
PL/SQL CURSOR (0) | 2014.10.14 |
PL/SQL 제어문 (0) | 2014.10.13 |
PL/SQL 변수 (0) | 2014.10.13 |
PL/SQL 시작하기 (0) | 2014.10.13 |