6. Oracle Subprogram ★★★
[기타SQL]/PL_SQL 2014. 10. 16. 12:28 |
지금까지의 PL/SQL 블록들은 전부 익명 블록인데, 익명블록이란 말그대로 PL/SQL블록에 이름이 정해져 있지 않다는 뜻이다. 익명블록들은 DECLARE 로 선언해 사용해서 정해진 이름이 없어도 잘 실행이 되었으나, 이름이 없으므로 저장이나 재 사용을 할 수 없다. 이럴 때 서브프로그램 또는 프로그램 단위를 호출해서 사용한다.
* 서브프로그램(프로그램단위) : 자주 사용되는 PL/SQL블록에 이름을 지정하고 생성해서 저장해 두었다가 필요할 경우에 호출해서 사용할 수 있도록 하는 것.
-> 대표유형 : 프로시저(PROCEDURE), 함수(Function), 패키지(PACKAGE), 트리거(TRIGGER)
프로시저(procedure), 함수(function)은 셋트이다.
익명블록 |
서브프로그램 |
이름이 지정되지 않은 PL/SQL 블록 |
이름이 지정된 PL/SQL블록 |
매번 사용시마다 컴파일된다. |
최초 실행될 때 한번만 컴파일 된다 |
데이터베이스에 저장되지 않는다 |
데이터베이스에 저장된다 |
다른 응용프로그램에서 호출 불가하다 |
다른 응용프로그램에서 호출 할 수 있다 |
값을 반환하지 않는다 |
함수일 경우 값을 반환 한다 |
파라미터를 사용할 수 없다 |
파라미터를 사용할 수 있다 |
1. PROCEDURE (프로시저) : 지정된 특정 처리를 실행하는 서브 프로그램의 한 유형.
- 단독(standalone)으로 실행되거나 다른 PROCEDURE나 다른 툴(Oracle Developer…) 또는 다른 환경(Pro*C…)등에서 호출되어 실행된다.
- 처음 생성 후 컴파일 할 때 오브젝트로서 데이터베이스 내에 저장되며 이후로 반복적으로 호출되어 실행될 때 별도의 컴파일 없이 p-code 로 바로 실행된다.
(일반 스크립트로 저장해서 @ 기호로 불러서 실행하는 것은 실행 할 때마다 컴파일을 해야 하므로 부하가 걸리지만, 오브젝트로 저장되는 서브 프로그램은 최초에 컴파일 되어서 저장되므로 이후 재 실행 시 컴파일이 별도로 필요하지 않다)
- PROCEDURE 생성 : CREATE PROCEDURE
- PROCEDURE 삭제 : DROP PROCEDURE
- PROCEDURE 수정 : ALTER PROCEDURE
[PROCEDURE 생성 문법 ]
CREATE [OR REPLACE] PROCEDURE PROCEDURE_name [( parameter1 [mode1] datatype1,
|
- OR REPLACE : 생성하고자 하는 PROCEDURE가 기존에 동일이름으로 존재할 경우, 기존의 내용을 현재의 내용으로 수정하는 옵션.
(해당 이름의 PROCEDURE를 삭제한 후 다시 생성한다.)
- parameter : PROCEDURE를 실행할 때 호출환경과 PROCEDURE간에 값을 주고 받을 때 사용되는 매개변수->모드(IN,OUT,IN OUT)에 따라 역할 다름.
파라미터를 선언할 때는 데이터형을 적고 데이터의 크기는 기록하지 않는다.
-> 형식 파라미터(formal parameter) : procedure를 생성할 때 선언부에 선언된 파라미터.
-> 실행 파라미터(actual parameter) : procedure를 실행할 때 형식 파라미터에 실제 값이나 변수를 할당/대응할 때 사용하는 파라미터.
- mode - in :사용자로부터 값을 입력받아 procedure로 전달. (기본값)
- out : procedure에서 호출환경(sql plus, 다른 프로시저 등)으로 값을 전달.
이 모드로 설정된 매개변수는 procedure내에서 읽을 수 없으며, 값을 저장하기만 하는 지역변수로 사용된다.
호출환경에서 이 매개변수로부터 값을 전달 받기 위해 환경변수가 선언되어 있어야 한다.
- in out : 호출환경과 procedure간에 값을 주고받는 지역변수. (읽기 쓰기 모두 가능)
* 파라미터 모드 별 비교
IN모드 |
OUT모드 |
IN OUT모드 |
기본모드 |
명시적으로 지정 |
명시적으로 지정 |
서브프로그램에 전달 |
호출환경에 반환 |
서브프로그램에 전달 / 호출환경에도 반환 |
형식 파라미터가 상수로 동작 |
초기화 되지 않은 변수 |
초기화된 변수 |
실제 파라미터가 리털럴, 표현식, 상수 또는 초기화된 변수가 될 수 있다. |
변수만 사용가능 |
변수만 사용가능 |
기본값 할당 가능 |
기본값 할당 불가 |
기본값 할당 불가 |
* 참고*
-PROCEDURE의 내용을 확인할 때 : USER_SOURCE 딕셔너리 활용. -에러내용을 보고 싶을 때 : SHOW ERRORS
|
실습 1. 부서번호가 20번 인 사람들의 job 을 ‘CLERK’ 으로 변경하는 PROCEDURE
SQL> CREATE OR REPLACE PROCEDURE update_20 --사용자로부터 값을 입력받지 않으므로, 매개변수를 별도로 사용하지 않음. 3 BEGIN --3번부터 7번까지가 익명블록이다. |
실습 2. 사번을 입력 받아 급여를 인상하는 PROCEDURE (사용자로부터 값을 입력 받아야 하므로 입력 매개변수를 사용)
SCOTT>SELECT empno , ename , sal FROM emp WHERE empno=7902; --vempno IN emp.empno%TYPE에서 IN생략(IN모드가 기본값이므로) 3 IS --3~4번사이 : PL/SQL엔진이 db에가서 원하는걸 꺼내와.
|
실습 3. 사번을 입력 받아 그 사원의 이름과 급여를 출력하는 PROCEDURE
SCOTT>CREATE OR REPLACE PROCEDURE ename_sal
SCOTT> set serveroutput on; SCOTT> EXEC ename_sal(7900); -- PROCEDURE실행(사원번호를 함께 입력해야됨.) |
- function은 return값이 있어서 바로 결과를 보여주지만, 프로시저는 return값이 없으므로 dbms_output.put_line을 사용하지 않으면 결과를 보여주지 않는다.
실습 4. OUT 모드 파라미터 사용 예
교수 테이블을 사용하여 PROCEDURE가 실행 될 때 교수번호를 입력 받은 후 해당 교수의 이름과 급여를 OUT 변수로 선언하여 해당 PROCEDURE 를 호출한 곳으로 OUT 하는 예제. (out변수를 사용하는 것과 작성된 procedure를 다른 함수나 procedure에서 어떻게 호출되어 사용되는지 익힐 수 있음.)
SCOTT>CREATE OR REPLACE PROCEDURE info_prof
|
-- 위에서 작성한 PROCEDURE 를 호출해서 값을 가져오는 익명 블록 PL/SQL문 작성.
SCOTT>DECLARE 6 DBMS_OUTPUT.PUT_LINE (v_name||' 교수의 급여는 '||v_pay||' 입니다.');
또 다른 방법으로 별도의 변수를 선언해서 값을 수행해서 받은 후 출력할 수 도 있다.
SCOTT>VARIABLE name VARCHAR2(10) SCOTT>VARIABLE pay NUMBER SCOTT>EXEC info_prof(1001 , :name , :pay); PL/SQL PROCEDURE successfully completed. SCOTT>PRINT name pay NAME ---------- 조인형 PAY ----------- 550 |
ex) 입/출고 담당하는 프로시저를 먼저돌려서 결과가나오면 out, 그결과를 재고프로시저에 보내서 재고프로시저가 돌아간다.
* 프로시저 이름 지정하는 방법.
① 위치 지정: PROCEDURE 를 실행하거나 호출할 때 실제 파라미터를 형식 파라미터와 동일한 순서로 나열. (위에서 사용한 방법)
(위치 지정 사용 예: info_prof(1001 , v_name , v_pay))
② 이름 지정: 실제 파라미터를 임의의 순서로 나열하며 연관 연산자(=>)를 사용하여 이름 지정
형식 파라미터를 실제 파라미터와 연관시킵니다.
[이름 지정 사용 예]
SCOTT>DECLARE
|
③ 혼합: 일부 실제 파라미터는 위치 지정으로 나열하고, 나머지는 이름 지정으로 나열(11g 부터 추가된 방법)
[사용예]
SCOTT> DECLARE - 이름: 조인형
|
실습 5. 생성된 PROCEDURE 의 내용 확인.
USER_SOURCE 딕셔너리를 활용.
SCOTT>DESC USER_SOURCE ; |
[PROCEDURE 연습문제 1]
신입 사원의 대한 아래 정보를 입력 받아 Emp 테이블에 등록하는 PROCEDURE 를 작성하세요.
신입사원의 정보는 아래와 같으며 나머지 컬럼의 값은 null 입니다. (PROCEDURE 이름과 변수 명은 임의대로 하세요)
* Empno : 4000
* Name : Smith
* Job : Clerk
* Manger no: 7900
* Salary : 3500
[PROCEDURE 연습문제2 ]
Emp 테이블을 사용하여 부서번호를 입력 받아서 보너스(comm) 를 아래의 조건으로 계산하여 사번, 이름, 부서번호, 급여, 보너스를 출력하는 PROCEDURE를 작성하세요. (PROCEDURE 이름과 변수 명은 적당하게 정하세요)
* 조건
1. Deptno = 10 이면 급여의 20%
2. Deptno = 20 이면 급여의 30%
3. Deptno = 30 이면 급여의 10%
4. 나머지는 0%
여기부터실습
[PROCEDURE 연습문제 3]
emp , dept 테이블을 사용하여 사원의 사원번호를 입력 받아서 아래처럼 그 사원의 사원번호와 ,이름, 부서명 ,급여, 상여금 을 출력하는 PROCEDURE 를 작성하세요. (PROCEDURE 이름과 변수명은 마음대로 하세요)
• 사 번 :
• 이 름 :
• 부서명 :
• 급 여 :
• 상여금 :
[PROCEDURE 연습문제 4]
아래 예시와 같이 대출금액과 대출 금리 , 기간을 입력하면 상환 내역을 출력하는 PROCEDURE 를 작성하세요.
단 상환방식은 원리금 균등방식으로 가정합니다. (아래 예시는 대출금액:1,000,000 원 , 대출금리 : 0.05(5%) , 기간: 12개월로 계산된 화면입니다)
2. FUNCTION (함수)
FUNCTION 과 PROCEDURE의 차이점
PROCEDURE 는 정해진 작업을 수행한 후 결과를 반환 할 수도 있고(OUT, IN OUT 모드 사용시) 반환 하지 않고 그냥 종료할 수도 있지만
함수는 정해진 작업을 수행 한 후 결과를 돌려준다(RETURN)는 부분만 다르다.
함수 생성 : CREATE FUNCTION
함수 삭제 : DROP FUNCTION
함수 수정 : ALTER FUNCTION
에러 확인 : SHOW ERRORS
[문 법]
CREATE [OR REPLACE] FUNCTION function_name
|
- OR REPLACE, PARAMETER, MODE : PROCEDURE와 동일.
- RETURN datatype (PROCEDURE와 다른 부분)
: 함수명으로 리턴할 데이터(값)의 형을 선언하는 부분. PL/SQL 함수 블록 내에서는 반드시 RETURN 문을 포함해야 하며, 그 때 RETURN 되는 데이터는 이 부분에서 선언한 데이터 형과 일치되어야 한다.
* 이렇게 생성됨 함수는 아래와 같은 곳에서 사용 가능하다.
- Query의 SELECT 리스트 또는 절
- WHERE 및 HAVIN G 절의 조건식
- Query의 CONNECT BY, START WITH, ORDER BY 및 GROUP BY 절
- IN SERT 문의 VALUES 절
- UPDATE 문의 SET 절
[함수 예제 1. 부서번호를 입력 받아 최고 급여액을 출력하는 함수 ]
SQL> CREATE OR REPLACE FUNCTION f_max_sal
SQL> SELECT f_max_sal(10) FROM dual;
|
[함수 예제 2: 부서번호를 입력 받은 후 해당 부서의 인원수를 구해주는 함수 ]
SQL> CREATE OR REPLACE FUNCTION count_mem
|
[함수 예제 3. 부서번호를 입력 받아 부서별로 평균 급여를 구해주는 함수]
SQL> CREATE OR REPLACE FUNCTION avg_sal
|
[함수 예제 4. 사원번호를 입력 받아 해당 사원의 부서명을 알려주는 함수 ]
SCOTT>CREATE OR REPLACE FUNCTION f_dname
|
[함수 예제 5. 생성된 함수 조회하기 ]
SCOTT>SELECT text function f_max_sal SELECT max(sal) into max_sal
|
3. ORACLE PACKAGE ( 패키지 )
* 패키지 : 특정 처리를 위해 관련된 PL/SQL 블록들(procedure, 함수, pl/sql데이터유형, 복합유형 등)이 논리적으로 하나의 그룹을 이루는 특수한 형태. (연관성이 높은 함수나 PROCEDURE 를 하나의 그룹으로 묶어서 관리하는 것.)
ex) 사원관리 업무 중에 입사관리, 연봉관리, 상여금관리, 근태관리, 퇴사자 관리 등의 업무가 많이 있을 경우 사원관리 라는 PACKAGE를 생성하고 그 세부에 각 작업을 수행하는 함수나 PROCEDURE 를 생성해서 관리할 때.
* package 구성.
① 선언부 : 해당 package에 사용될 함수나 procedure,변수등에 대한 정의를 선언하는 부분. (목차 같은 의미)
② 몸체부 : 선언부에서 선언된 함수나 procedure등이 실제 code로 구현되는 부분. (선언부에 선언되지 않더라도 package몸체부에 사용될 수는 있지만 별로 권장하지 않는다.)
- 만약 생성된 PACKAGE의 선언부가 변경되었다면 무조건 PACKAGE 몸체부는 다시 재 생성해야하며 PACKAGE를 참조(호출)하는 서브 프로그램들도 재 번역(recompile)해야 하지만, 반대로 PACKAGE 몸체부만 변경되었다면 PACKAGE 선언부와 다른 관련 서브프로그램에 영향을 주지 않고 몸체부만 재 생성하면 된다.
1) PACKAGE 구조 :PACKAGE 선언부(Specification)/PACKAGE 몸체부(Body) 로 구성.
(1) PACKAGE 선언부 생성
[ 문 법 ]
CREATE [OR REPLACE] PACKAGE PACKAGE_name
|
- public type and item declarations : 변수,상수, 명시적 커서, 사용자 정의 예외, PRAGMA 등을 선언. (모두 public이라는 특징을 갖는다.)
(2) PACKAGE 몸체부(Body) 생성
[문 법]
CREATE [OR REPLACE] PACKAGE BODY PACKAGE_name END PACKAGE_name ;
|
- private type and item declarations : 변수, 상수, 명시적커서, 사용자정의 예외, pragma등을 선언.
- subprogram bodies : 실제 작동할 서브프로그램(procedure, 함수 등)을 기록. 단 서브프로그램의 순서를 주의해야 한다. 기본적으로 참조되는 변수든 서브프로그램이든 참조하는 서브프로그램보다는 먼저 정의돼야 한다. 일반적으로 public의 서브프로그램은 마지막 부분에 정의한다.
2) PACKAGE 실행하기
: 생성된 PACKAGE 오브젝트에 대한 실행권한을 가진 사용자만이 PACKAGE를 호출하여 실행할 수 있다.
3) PACKAGE 삭제
: PACKAGE 선언부와 PACKAGE 몸체부를 모두 삭제할 수 도 있고, PACKAGE 몸체부만 삭제할 수도 있다.
DROP PACKAGE PACKAGE_name ;
|
4) PACKAGE 사용 예
예1) Emp table 에서 총 급여합계와 평균 급여를 구하는 emp_sal_mgr PACKAGE.
-- PACKAGE 선언부
-- PACKAGE 몸체부 22 BEGIN
|
-- 생성된 패키지를 실행.
|
-- 위 PACKAGE 실행결과가 맞는지 SQL 을 직접 수행해서 검증.
|
이하 예제는 생략함.
예2) member 테이블에 등록되어 있는 회원들의 성별과 아이디 검색과 비밀번호를 검색해 주는 PACKAGE. (실제 사용하는 쿼리라 양많고 복잡해)
사용자 정보가 들어있는 member 테이블을 사용하여 회원 관리를 하는 PL/SQL PACKAGE 를 생성.
* 아래와 같은 procedure로 구성.
- 사용자 이름을 입력 받은 후 남자인지 여자인지를 구분하는 pro_gender 프로시저 ,
- 사용자 이름과 주민번호를 입력 받아 회원의 아이디를 찾아주는 pro_find_id 프로시저 ,
- 사용자 아이디와 연상단어를 입력 받아 회원의 비밀번호를 알려주는 pro_find_pw 프로시저
[준비]
|
Step 1. PACKAGE 선언부 생성.
|
Step 2. PACKAGE BODY부 생성.
31 v_jumin2 IN member.jumin%TYPE ) 37 exception_noname EXCEPTION ; 75 SELECT count(*) INTO v_count |
Step 3. 생성된 PACKAGE를 테스트 합니다.
-- 현재 테이블에 들어 있는 데이터를 조회합니다. SCOTT>SELECT * FROM member ; |
- pro_gender PROCEDURE 를 테스트 합니다.
SCOTT>EXEC pkg_member.pro_gender('홍길동') ; |
|
- pro_find_id PROCEDURE 를 테스트합니다.
이 PROCEDURE 는 이름과 주민번호를 입력하면 아이디를 검색해 주는 기능을 합니다. |
- 주민번호 잘못 입력한 후 에러 발생 확인
|
- 이름 잘못 입력한 후 에러발생 확인
|
- pro_find_pw PROCEDURE 를 테스트 합니다.
|
- 아이디를 틀리게 넣고 에러를 확인
SCOTT>EXEC pkg_member.pro_find_pw('aaaa','유관순') ; ORA-06512: at "SCOTT.PKG_MEMBER", line 94 ORA-06512: at line 1 |
- 아이디는 맞고 연상 단어를 잘못 넣은 후 에러 확인
SCOTT>EXEC pkg_member.pro_find_pw('simson','홍길동') ; |
5) 생성된 PACKAGE 조회하기
- 선언부 조회하기
SCOTT>SELECT text
2 FROM user_source
3 WHERE type=' PACKAGE';
TEXT
--------------------------------------------------------------------------------
PACKAGE emp_total as
PROCEDURE emp_sum;
PROCEDURE emp_avg;
end emp_total;
- BODY 부 조회하기
SCOTT>SELECT text
2 FROM user_source
3 WHERE type like ' PACKAGE BODY';
TEXT
--------------------------------------------------------------------------------
package body emp_total as
PROCEDURE emp_sum
IS
cursor emp_total_sum IS
SELECT count(*),sum(nvl(sal,0))
FROM emp;
total_num NUMBER ;
total_sum NUMBER ;
begIN
open emp_total_sum ;
fetch emp_total_sum into total_num ,total_sum ;
dbms_output.put_line ('총인원수: '||total_num||' , 급여합계: '||total_sum);
close emp_total_sum;
end emp_sum ;
PROCEDURE emp_avg
IS
cursor emp_total_avg IS
SELECT count(*), avg(nvl(sal,0))
FROM emp;
total_num NUMBER ;
total_avg NUMBER ;
begin
open emp_total_avg ;
fetch emp_total_avg into total_num , total_avg;
dbms_output.put_line ('총인원수: '||total_num||' , 급여평균: '||total_avg);
close emp_total_avg ;
end emp_avg;
end emp_total;
28 rows selected.
4. TRIGGER (트리거)
1)개요
2)주요 TRIGGER유형
(1) 단순 DML TRIGEER
- before trigger : 테이블에서 DML이벤트를 trigger하기전에 trigger 본문을 실행.
- after trigger : 테이블에서 DML이벤트를 trigger한 후에 trigger 본문을 실행.
- instead of trigger : (잘안씀)
ex) 입고가 되면 재고테이블에 반영.
DML TRIGGER는 다시 문장 TRIGGER 와 행 TRIGGER 로 나누어집니다.
문장 TRIGGER는 대상이 모든 행이며 영향을 받는 행이 전혀 없더라도 TRIGGER가 무조건 한번은 실행된다.
예를 들어서 특정 테이블에 데이터를 입력할 수 있는 시간을 지정하는 경우에 어떤 데이터가 들어오든지 TRIGGER 를 적용하게 됩니다. 또는 특정 테이블에 데이터를 입력할 수 있는 계정을 등록하는 등과 같이 테이블에 들어 있는 행이 대상이 아니라 테이블 자체를 대상으로 TRIGGER를 작동하게 만들 경우에 문장 TRIGGER를 사용하면 됩니다.
행 TRIGGER는 테이블에 있는 특정 행이 TRIGGER 이벤트의 영향을 받을 경우 해당 TRIGGER가 실행되고, TRIGGER 이벤트의 영향을 받는 행이 없을 경우에는 TRIGGER는 실행되지 않습니다.
즉 특정행만 이 TRIGGER 의 영향을 받는 것입니다. 예를 들어 제품번호가
100 번인 제품만 입력이 안되게 막고 싶을 경우에 다른 행은 TRIGGER 와 상관없지만 100번
제품은 TRIGGER 가 적용되어 입력이 안 되는 것입니다. 이처럼 특정 행에게만 영향을 주는
TRIGGER 를 행 TRIGGER 라고 하며 행 TRIGGER 로 생성하려면 FOR EACH ROW 라는 구절을
사용하면 됩니다.
바로 예제로 점프
5) TRIGGER 예제
( 아래 실습을 하기 전에 아래와 같이 scott 사용자에게 CREATE TRIGGER 권한을 할당하세요)
SYS> GRANT create tigger TO scott ;
예 1) 테이블에 데이터를 입력할 수 있는 시간 지정하기 (테이블 전체가 대상이므로 문장 레벨 TRIGGER 사용.)
테스트를 하기 위해 아래와 같이 연습용 테이블 t_order 테이블을 생성합니다.
SCOTT>CREATE TABLE t_order_tab
2 ( no NUMBER ,
3 ord_code VARCHAR2(10),
4 ord_date DATE ) ;
Table created.
위에서 생성한 테이블에 데이터를 입력할 때 입력시간이 18:40 분에서 18:50 분일 경우만 입력을 허용하고 그 외 시간일 경우는 에러를 발생시키는 TRIGGER 생성하겠습니다.
SCOTT>CREATE OR REPLACE TRIGGER t_order
2 BEFORE INSERT ON t_order_tab -- t_oorder_tab에 insert되기전에!!
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 /
trigger created.
SCOTT>SELECT SYSDATE FROM DUAL;
SYSDATE
------------------------
2014-04-07:18:43:51 – 입력 허용 시간 입니다.
SCOTT>INSERT INTO t_order_tab
2 VALUES(1,'C100',SYSDATE);
1 row created. – 정상적으로 입력됩니다.
SCOTT>SELECT SYSDATE FROM DUAL;
SYSDATE
------------------------
2014-04-07:18:53:06 -- 입력허용시간이 지났습니다
SCOTT>INSERT INTO t_order_tab
2 VALUES(2,'C200',SYSDATE);
INSERT INTO t_order_tab
*
ERROR at line 1:
ORA-20100: 허용시간 아닙니다 -- 의도하던 에러가 발생합니다
ORA-06512: at "SCOTT.T_ORDER", line 3
ORA-04088: error during execution of trigger 'SCOTT.T_ORDER'
예 2)
테이블에 입력될 데이터 값을 지정하고 그 값 이외에는 에러를 발생시키는 TRIGGER 를 생성합
니다.
위 문장 레벨 TRIGGER 실습에서 생성한 테이블로 계속 실습하겠습니다.
이번에는 제품코드가 ‘C100’ 번인 제품이 입력될 경우 입력을 허용하고 나머지 제품은 모두 에러
를 발생시키는 TRIGGER 를 작성하겠습니다. 이 경우는 테이블에 있는 행이 TRIGGER 의 검사 대
상이므로 행 레벨 TRIGGER을 사용합니다.
SCOTT>CREATE OR REPLACE TRIGGER t_order2
-- 신규 내용을 입력하는데 앞에서 생성한 문장레벨 TRIGGER로 인해 입력이 안됩니다.
|
예 3) TRIGGER 의 작동 조건을 WHEN 절로 더 구체적으로 지정합니다.
이번 예는 ORD_CODE 가 ‘C500’ 인 제품에 대해서만 19:30 분부터 19:35분까지만 입력을 허용하
는 TRIGGER 입니다. 당연히 다른 제품코드는 시간에 관계없이 정상적으로 입력이 됩니다.
SCOTT>CREATE OR REPLACE TRIGGER t_order3 6 IF (TO_CHAR(SYSDATE,'HH24:MI') NOT BETWEEN '19:30' AND '19:35') THEN
|
예 4 ) 특정 테이블에 입력할 수 있는 계정을 지정하기
(테이블 자체가 대상이므로 문장 TRIGGER 를 사용합니다.)
실습을 위해 새로운 테이블을 생성합니다.
SCOTT>CREATE TABLE t_test1 (no NUMBER );
Table created.
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 /
trigger created.
테스트를 위해 새로운 사용자 계정 user1 을 생성하고 필요한 권한을 할당합니다..
SCOTT>conn / as sysdba
Connected.
SYS>CREATE USER user1 IDENTIFIED BY user1
2 DEFAULT TABLESPACE users
3 TEMPORARY TABLESPACE temp;
User created.
SYS>GRANT connect , resource TO user1;
Grant succeeded.
SYS>GRANT INSERT ON scott.t_test1 TO user1;
Grant succeeded.
SCOTT>CONN user1/user1
Connected.
USER1>INSERT INTO scott.t_test1 VALUES (1);
INSERT INTO scott.t_test1 VALUES (1)
*
ERROR at line 1:
ORA-20001: 허락된 계정이 아닙니다!!!
ORA-06512: at "SCOTT.T_USERCHECK", line 3
ORA-04088: error during execution of TRIGGER 'SCOTT.T_USERCHECK'
예 5) 기존 테이블(t_test1) 에 데이터가 업데이트 될 때 기존 내용을 백업테이블(t_test2)으로
옮겨놓는 TRIGGER 를 생성합니다. 삭제되는 특정 행이 TRIGGER의 대상이므로 Row 레벨
TRIGGER 를 사용합니다.
SCOTT> CREATE TABLE t_test1
2 (no NUMBER , name VARCHAR2(10));
Table created.
SCOTT> CREATE TABLE t_test2
2 AS SELECT * FROM t_test1;
Table created.
SCOTT> INSERT INTO t_test1 VALUES (1,'AAA');
1 row created.
SCOTT> INSERT INTO t_test1 VALUES (2,'BBB');
1 row created.
SCOTT> COMMIT;
Commit complete.
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 /
TRIGGER created.
위 예에서 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
예 6 )
기존 테이블(t_test3) 의 데이터가 delete 될 때 기존 내용을 백업 테이블(t_test4)로 이동시키며
이때 백업 테이블에 삭제한 시간, 삭제 전 데이터, 삭제한 사용자 이름을 모두 기록하는
TRIGGER를 생성합니다.
SCOTT> CREATE TABLE t_test3
2 ( no NUMBER ,
3 name VARCHAR2(10));
Table created.
SCOTT> CREATE TABLE t_test4
2 ( no NUMBER ,
3 name VARCHAR2(10),
4 time DATE ,
5 username VARCHAR2(10)) ;
Table created.
SCOTT> INSERT INTO t_test3 VALUES (1,'AAA');
1 row created.
SCOTT> INSERT INTO t_test3 VALUES (2,'BBB');
1 row created.
SCOTT> COMMIT ;
Commit complete.
SCOTT> SELECT * FROM t_test3;
NO NAME
---------- -------------
1 AAA
2 BBB
SCOTT> SELECT * FROM t_test4;
no rows selected
SCOTT> CREATE OR REPLACE TRIGGER d_trigger
2 AFTER delete ON t_test3
3 FOR EACH ROW
4 BEGIN
5 INSERT INTO t_test4
6 VALUES(:OLD.no, :OLD.name , SYSDATE , USER );
7 END ;
8 /
trigger created.
SCOTT> SELECT * FROM t_test3;NO NAME
---------- ---------
1 AAA
2 BBB
SCOTT> SELECT * FROM t_test4;
no rows selected
SCOTT> DELETE FROM t_test3 WHERE no=1;
1 row deleted.
SCOTT> SELECT * FROM t_test3;
NO NAME
---------- -----------
2 BBB
SCOTT>SELECT * FROM t_test4;
NO NAME TIME USERNAME
---------- ---------- ---------------- ----------------
1 AAA 30-NOV-13 SCOTT
예 7 ) 사용자의 로그온, 로그오프 정보를 테이블에 기록하는 TRIGGER 생성
이번 실습은 아래와 같이 관리자 계정인 SYSTEM 계정으로 로그인 해서 작업하세요.
- TRIGGER를 작성합니다. SYSTEM> CREATE OR REPLACE TRIGGER t_logoff 6 END ;
|
예 8) 특정 사용자가 DDL 을 수행하지 못하게 막는 TRIGGER
오라클 8.1.6 버전부터 제공하는 SYSTEM TRIGGER 기능을 이용하여 특정 사용자가 DDL 을 사용
하는 것을 제어 할 수 있습니다. 현업에서 아주 많이 사용되고 있는 TRIGGER 예 입니다.
이 실습을 하기 위해서 아래와 같이 관리자 계정으로 로그인 하세요.
SCOTT>CONN sys/oracle as sysdba ;
CASE 1. scott 사용자가 DDL 모두를 사용하지 못하게 막는 TRIGGER
SYS>CREATE OR REPLACE TRIGGER scott_no_ddl
2 BEFORE DDL ON scott.schema
3 BEGIN
4 RAISE_APPLICATION_ERROR(-20001,'DDL 은 사용할 수 없습니다!!');
5 END;
6 /
trigger created.
SYS>CONN scott/tiger
Connected.
SCOTT>CREATE TABLE test_ddl_1
2 (no NUMBER ) ;
CREATE TABLE test_ddl_1
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: DDL 은 사용할 수 없습니다!!
ORA-06512: at line 2
예상했던 에러가 발생하는 것을 확인 할 수 있습니다.
다음 실습을 위해 위 TRIGGER 를 삭제합니다.
SCOTT>CONN sys/oracle as sysdba
Connected.
SYS>DROP TRIGGER scott_no_ddl;
TRIGGER dropped.
CASE 2. scott 계정에서 Table 과 Index 에만 DDL을 사용 못하게 막는 TRIGGER
SYS>CREATE OR REPLACE TRIGGER scott_no_ddl_2
2 BEFORE DDL ON scott.schema
3 WHEN (ora_dict_obj_type='TABLE' OR ora_dict_obj_type='INDEX')
4 BEGIN
5 RAISE_APPLICATION_ERROR(-20002,'Table과 Index에는 DDL 사용할 수 없습니다!');
6 END;
7 /
trigger created.
SYS>CONN scott/tiger
Connected.
SCOTT>CREATE TABLE ddl_test_1 (no NUMBER );
CREATE TABLE ddl_test_1 (no NUMBER )
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20002: Table과 Index에는 DDL 사용할 수 없습니다!
ORA-06512: at line 2
SCOTT>CREATE INDEX idx_emp_no ON emp(empno);
create Index idx_emp_no on emp(empno)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20002: Table과 Index에는 DDL 사용할 수 없습니다!
ORA-06512: at line 2
SCOTT>CRATE VIEW v_emp
2 AS SELECT empno , ename FROM emp ;
View created.
SCOTT>CONN sys/oracle as sysdba
Connected.
SYS>DROP TRIGGER scott_no_ddl_2;
TRIGGER dropped. <- 다음 실습을 위해 위에서 생성한 TRIGGER 를 삭제합니다.
CASE 3. Scott schema 의 Drop 과 Truncate 작업을 막는 TRIGGER
SCOTT>CONN sys/oracle as sysdba
Connected.
SYS>CREATE OR REPLACE TRIGGER scott_no_ddl_3
2 BEFORE DROP OR TRUNCATE ON scott.schema
3 BEGIN
4 RAISE_APPLICATION_ERROR(-20003,'Drop 과 Truncate 사용 불가입니다!');
5 END;
trigger created.
SYS>CONN scott/tiger
Connected.
SCOTT>DROP VIEW v_emp;
drop view v_emp
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20003: Drop 과 Truncate 사용 불가입니다!
ORA-06512: at line 2
SCOTT>TRUNCATE TABLE emp;
truncate table emp
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20003: Drop 과 Truncate 사용 불가입니다!
ORA-06512: at line 2
이상으로 다양한 TRIGGER 활용 예제들을 살펴보았습니다
TRIGGER 를 끝으로 PL/SQL 기초과정을 마치겠습니다.
jyc8618
'[기타SQL] > PL_SQL' 카테고리의 다른 글
5. Oracle Exception (예외처리) (0) | 2014.10.15 |
---|---|
4. PL/SQL Cursor(커서) 정리해야됨. (1) | 2014.10.14 |
3. PL/SQL 제어문. (0) | 2014.10.13 |
2. PL/SQL 변수. (0) | 2014.10.13 |
1. ORACLE PL/SQL 시작하기 (0) | 2014.10.13 |