익명 블록 | 저장 서브프로그램 | |
---|---|---|
이름 | 이름 없음 | 이름 지정 |
오라클 저장 | 저장할 수 없음 | 저장함 |
컴파일 | 실행할 때마다 컴파일 | 저장할 때 한 번 컴파일 |
공유 | 공유할 수 없음 | 공유하여 사용 가능 |
다른 응용 프로그램에서의 호출 가능 여부 | 호출할 수 없음 | 호출 가능 |
서브프로그램 | 용도 |
---|---|
저장 프로시저(stored procedure) | 일반적으로 특정 처리 작업 수행을 위한 서브프로그램으로 SQL문에서는 사용할 수 없다. |
저장 함수(stored function) | 일반적으로 특정 연산을 거친 결과 값을 반환하는 서브프로그램으로 SQL문에서 사용할 수 있다. |
패키지(Package) | 저장 서브프로그램을 그룹화하는데 사용한다. |
트리거(trigger) | 특정 상황(이벤트)이 발생할 때 자동으로 연달아 수행할 기능을 구현하는 데 사용한다. |
CREATE [OR REPLACE] PROCEDURE 프로시저 이름
IS | AS
선언부
BEGIN
실행부
EXCEPTION
예외 처리부
END [프로시저 이름];
EXECUTE 프로시저 이름;
CREATE OR REPLACE PROCEDURE pro_noparam
IS
V_EMPNO NUMBER(4) := 7788;
V_ENAME VARCHAR2(10);
BEGIN
V_ENAME := 'SCOTT';
DBMS_OUTPUT.PUT_LINE('V_EMPNO : ' || V_EMPNO);
DBMS_OUTPUT.PUT_LINE('V_ENAME : ' || V_ENAME);
END;
/
SET SERVEROUTPUT ON;
EXECUTE pro_noparam;
BEGIN
pro_noparam;
END;
/
USER_SOURCE의 열 | 설명 |
---|---|
NAME | 서브프로그램(생성 객체) 이름 |
TYPE | 서브프로그램 종류(PROCEDURE, FUNCTINO 등) |
LINE | 서브프로그램에 작성한 줄 번호 |
TEXT | 서브프로그램에 작성한 소스 코드 |
SELECT *
FROM USER_SOURCE
WHERE NAME = 'PRO_NOPARAM';
SELECT TEXT
FROM USER_SOURCE
WHERE NAME = 'PRO_NOPARAM';
DROP PROCEDURE PRO_NOPARAM;
CREATE [OR REPLACE] PROCEDURE 프로시저 이름
[(파라미터 이름1 [modes] 자료형 [ := | DEFUALT 기본값],
파라미터 이름2 [modes] 자료형 [ := | DEFUALT 기본값],
...
파라미터 이름N [modes] 자료형 [ := | DEFUALT 기본값],
)]
IS | AS
선언부
BEGIN
실행부
EXCEPTION
예외 처리부
END [프로시저 이름];
파라미터 모드 | 설명 |
---|---|
IN | 지정하지 않으면 기본 값으로 프로시저를 호출할 떄 값을 입력 받는다.(입력, void) |
OUT | 호출할 떄 값을 반환한다.(입력X, return) |
IN OUT | 호출할 때 값을 입력받은 후 실행 결과 값을 반환한다.(입력, return) |
CREATE OR REPLACE PROCEDURE pro_param_in
(
param1 IN NUMBER,
param2 NUMBER,
param3 NUMBER := 3,
param4 NUMBER DEFAULT 4
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('param1 : ' || param1);
DBMS_OUTPUT.PUT_LINE('param2 : ' || param2);
DBMS_OUTPUT.PUT_LINE('param3 : ' || param3);
DBMS_OUTPUT.PUT_LINE('param4 : ' || param4);
END;
/
EXECUTE pro_param_in(1,2,9,8);
EXECUTE pro_param_in(1, 2);
(
param1 IN NUMBER,
param2 NUMBER := 3,
param3 NUMBER,
param4 NUMBER DEFAULT 4
)
EXECUTE pro_param_in(param1 => 10, param2 => 20);
종류 | 설명 |
---|---|
위치 지정 | 지정한 파라미터 순서대로 값을 지정하는 방식 |
이름 지정 | => 연산자로 파라미터 이름을 명시하여 값을 지정하는 방식 |
혼합 지정 | 일부 파라미터는 순서대로 값만 지정하고 일부 파라미터는 => 연산자로 값을 지정하는 방식 |
CREATE OR REPLACE PROCEDURE pro_param_out
(
in_empno IN EMP.EMPNO%TYPE,
out_ename OUT EMP.ENAME%TYPE,
out_sal OUT EMP.SAL%TYPE
)
IS
BEGIN
SELECT ENAME, SAL INTO out_ename, out_sal
FROM EMP
WHERE EMPNO = in_empno;
END pro_param_out;
/
DECLARE
v_ename EMP.ENAME%TYPE;
v_sal EMP.SAL%TYPE;
BEGIN
pro_param_out(7788, v_ename, v_sal);
DBMS_OUTPUT.PUT_LINE('ENAME : ' || v_ename);
DBMS_OUTPUT.PUT_LINE('SAL : ' || v_sal);
END;
/
CREATE OR REPLACE PROCEDURE pro_param_inout
(
inout_no IN OUT NUMBER
)
IS
BEGIN
inout_no := inout_no * 2;
END pro_param_inout;
/
DECLARE
no NUMBER;
BEGIN
no := 5;
pro_param_inout(no);
DBMS_OUTPUT.PUT_LINE('no : ' || no);
END;
/
CREATE OR REPLACE PROCEDURE pro_err
IS
err_no NUMBER;
BEGIN
err_no = 100;
DBMS_OUTPUT.PUT_LINE('err_no : ' || err_no);
END pro_err;
/
SHOW ERRORS;
SHOW ERR 프로그램 종류 프로그램 이름;
SHOW ERR PROCEDURE pro_err;
SELECT *
FROM USER_ERRORS
WHERE NAME = 'PRO_ERR';
특징 | 프로시저 | 함수 |
---|---|---|
실행 | EXECUTE 명령어 또른 다른 PL/SQL 서브 프로그램 내에서 호출하여 실행 | 변수를 사용한 EXECUTE 명령어 또는 다른 PL/SQL 서브프로그램에서 호출하여 실행하거나 SQL무네서 직접 실행 가능 |
파라미터 지정 | 필요에 따라 지정하지 않을 수도 있고, 여러 개를 지정할 수도 있으며 IN, OUT, IN OUT 세 가지 모드를 사용할 수 있다. | 프로시저와 같게 지정하지 않을 수도 있고 여러 개 지정할 수도 있지만 IN 모드(또는 생략)만 사용 |
값의 반환 | 실행 후의 값의 반환이 없을 수도 있고, OUT, IN OUT 모드의 파라미터 수에 따라 여러 개 값을 반환할 수 있다. | 반드시 하나의 값을 반환해야 하며, 값의 반환은 프로시저와 달리 OUT, IN OUT 모드의 파라미터를 사용하는 것이 아니라 RETURN절과 RETURN문을 통해 반환 |
CREATE [OR REPLACE] FUNCTION 함수 이름
[(파라미터 이름1 [IN] 자료형1,
파라미터 이름2 [IN] 자료형2,
...
파라미터 이름N [IN] 자료형N
)]
RETURN 자료형
IS | AS
선언부
BEGIN
실행부
RETURN (반환값);
ECXEPTION
예외 처리부
END [함수 이름];
CREATE OR REPLACE FUNCTION func_aftertax(
sal IN NUMBER
)
RETURN NUMBER
IS
tax NUMBER := 0.05;
BEGIN
RETURN (ROUND(sal - (sal * tax)));
END func_aftertax;
/
DECLARE
aftertax NUMBER;
BEGIN
aftertax := func_aftertax(3000);
DBMS_OUTPUT.PUT_LINE('after-tax income : ' || aftertax);
END;
/
SELECT func_aftertax(3000)
FROM DUAL;
SELECT EMPNO, ENAME, SAL, func_aftertax(SAL) AS AFTERTAX
FROM EMP;
DROP FUNCTION func_aftertax;
장점 | 설명 |
---|---|
모듈성 | 서브프로그램을 포함한 여러 PL/SQL 구성 요소를 모듈화 할 수 있다. 모듈성은 잘 묶어둔다는 뜻으로, 프로그램의 이해를 쉽게 하고 패키지 사이의 상호 작용을 더 간편하고 명료하게 해주는 역할을 한다. 즉, PL/SQL로 제작한 프로그램의 사용 및 관리에 큰 도움을 준다. |
쉬운 응용 프로그램 설계 | 패키지에 포함할 서브 프로그램은 완벽하게 완성되지 않아도 정의가 가능하다. 이 때문에 전체 소스 코드를 다 작성하기 전에 미리 패키지에 저장할 서브프로그램을 지정할 수 있으므로 설계가 수월해진다. |
정보 은닉 | 제작 방식에 따라 패키지에 포함하는 서브 프로그램의 외부 노출 여부 또는 접근 여부를 지정할 수 있다. 즉, 서브프로그램을 사용할 때 보안을 강화할 수 있다. |
기능성 향상 | 패키지 내부에서는 서브프로그램 외에 변수, 커서, 예외 등도 각 세션이 유지되는 동안 선언해서 공용(public)으로 사용할 수 있다. 예를 들어 특정 커서 데이터는 세션이 종료되기 전까지 보존되므로 여러 서브프로그램에서 사용할 수 있다. |
성능 향상 | 패키지를 사용할 때 패키지에 포함된 모든 서브프로그램이 메모리에 한 번에 로딩되는데, 메모리에 로딩된 후의 호출은 디스크 I/O를 일으키지 않으므로 성능이 향상된다. |
⇒ 패키지는 PL/SQL 서브 프로그램의 제작, 사용, 관리, 보안, 성능 등에 좋은 영향을 끼친다.
CREATE [OR REPLACE] PACKAGE 패키지 이름
IS | AS
서브프로그램을 포함한 다양한 객체 선언
END [패키지 이름];
CREATE OR REPLACE PACKAGE pkg_example
IS
spec_no NUMBER := 10;
FUNCTION func_aftertax(sal NUMBER) RETURN NUMBER;
PROCEDURE pro_emp(in_empno IN EMP.EMPNO%TYPE);
PROCEDURE pro_dept(in_deptno IN DEPT.DEPTNO%TYPE);
END;
/
SELECT TEXT
FROM USER_SOURCE
WHERE TYPE = 'PACKAGE'
AND NAME = 'PKG_EXAMPLE';
DESC pkg_example;
CREATE [OR REPLACE] PACKAGE BODY 패키지 이름
IS | AS
패키지 명세에서 선언한 서브프로그램을 포함한 여러 객체를 정의
경우에 따라 패키지 명세에 존재하지 않는 객체 및 서브프로그램도 정의 가능
END [패키지 이름];
CREATE OR REPLACE PACKAGE BODY pkg_example
IS
body_no NUMBER := 10;
FUNCTION func_aftertax(sal NUMBER) RETURN NUMBER
IS
tax NUMBER := 0.05;
BEGIN
RETURN (ROUND(sal - (sal * tax)));
END func_aftertax;
PROCEDURE pro_emp(in_empno IN EMP.EMPNO%TYPE)
IS
out_ename EMP.ENAME%TYPE;
out_sal EMP.SAL%TYPE;
BEGIN
SELECT ENAME, SAL INTO out_ename, out_sal
FROM EMP
WHERE EMPNO = in_empno;
DBMS_OUTPUT.PUT_LINE('ENAME : ' || out_ename);
DBMS_OUTPUT.PUT_LINE('SAL : ' || out_sal);
END pro_emp;
PROCEDURE pro_dept(in_deptno IN DEPT.DEPTNO%TYPE)
IS
out_dname DEPT.DNAME%TYPE;
out_loc DEPT.LOC%TYPE;
BEGIN
SELECT DNAME, LOC INTO out_dname, out_loc
FROM DEPT
WHERE DEPTNO = in_deptno;
DBMS_OUTPUT.PUT_LINE('DNAME : ' || out_dname);
DBMS_OUTPUT.PUT_LINE('LOC : ' || out_loc);
END pro_dept;
END;
/
CREATE [OR REPLACE] PACKAGE 패키지 이름
IS | AS
서브프로그램 종류 서브프로그램 이름(파라미터 정의);
서브프로그램 종류 서브프로그램 이름(개수나 자료형, 순서가 다른 파라미터 정의);
END [패키지 이름];
CREATE OR REPLACE PACKAGE pkg_overload
IS
PROCEDURE pro_emp(in_empno IN EMP.EMPNO%TYPE);
PROCEDURE pro_emp(in_ename IN EMP.ENAME%TYPE);
END;
/
CREATE OR REPLACE PACKAGE BODY pkg_overload
IS
PROCEDURE pro_emp(in_empno IN EMP.EMPNO%TYPE)
IS
out_ename EMP.ENAME%TYPE;
out_sal EMP.SAL%TYPE;
BEGIN
SELECT ENAME, SAL INTO out_ename, out_sal
FROM EMP
WHERE EMPNO = in_empno;
DBMS_OUTPUT.PUT_LINE('ENAME : ' || out_ename);
DBMS_OUTPUT.PUT_LINE('SAL : ' || out_sal);
END pro_emp;
PROCEDURE pro_emp(in_ename IN EMP.ENAME%TYPE)
IS
out_ename EMP.ENAME%TYPE;
out_sal EMP.SAL%TYPE;
BEGIN
SELECT ENAME, SAL INTO out_ename, out_sal
FROM EMP
WHERE ENAME = in_ename;
DBMS_OUTPUT.PUT_LINE('ENAME : ' || out_ename);
DBMS_OUTPUT.PUT_LINE('SAL : ' || out_sal);
END pro_emp;
END;
/
BEGIN
DBMS_OUTPUT.PUT_LINE('--pkg_example.func_aftertax(3000)--');
DBMS_OUTPUT.PUT_LINE('after-tax:' || pkg_example.func_aftertax(3000));
DBMS_OUTPUT.PUT_LINE('--pkg_example.pro_emp(7788)--');
pkg_example.pro_emp(7788);
DBMS_OUTPUT.PUT_LINE('--pkg_example.pro_dept(10)--' );
pkg_example.pro_dept(10);
DBMS_OUTPUT.PUT_LINE('--pkg_overload.pro_emp(7788)--' );
pkg_overload.pro_emp(7788);
DBMS_OUTPUT.PUT_LINE('--pkg_overload.pro_emp(''SCOTT'')--' );
pkg_overload.pro_emp('SCOTT');
END;
/
패키지 명세와 본문을 한 번에 삭제하기
DROP PACKAGE 패키지 이름;
패키지의 본문만을 삭제
DROP PACKAGE BODY 패키지 이름;
오라클에서 트리거는 데이터베이스 안의 특정 상황이나 동작, 즉 이벤트가 발생할 경우에 자동으로 실행되는 기능을 정의하는 PL/SQL 서브 프로그램이다.
종류 | 설명 |
---|---|
DML 트리거 | INSERT, UPDATE, DELETE와 같은 DML 명령어를 기점으로 동작함 |
DDL 트리거 | CREATE, ALTER, DROP과 같은 DDL 명령어를 기점으로 동작함 |
INSTEAD OF 트리거 | 뷰(View)에 사용하는 DML 명령어를 기점으로 동작함 |
시스템(system) 트리거 | 데이터베이스나 스키마 이벤트로 동작함 |
단순(simple) 트리거 | 다음 각 시점(timing point)에 동작함 - 트리거를 작동시킬 문장이 실행되기 전 시점 - 트리거를 작동시킬 문장이 실행된 후 시점 - 트리거를 작동시킬 문장이 행에 영향을 미치기 전 시점 - 트리거를 작동시킬 문장이 행에 영향을 준 후 시점 |
복합(compund) 트리거 | 단순 트리거의 여러 시점에 동작함 |
CREATED [OR REPLACE] TRUGGER 트리거 이름
BEFORE | AFTER
INSERT | UPDATE | DELETE ON 테이블 이름
REFERENCING OLD as old | New as new
FOR EACH ROW WHEN 조건식
FOLLOWS 트리거 이름2, 트리거 이름3, ...
ENABLE | DISABLE
DECLARE
선언부
BEGIN
실행부
EXCEPTION
예외 처리부
END;
REFERENCING OLD as old | New as new
:FOR EACH ROW WHEN 조건식
:CREATE TABLE EMP_TRG
AS SELECT * FROM EMP;
CREATE OR REPLACE TRIGGER trg_emp_nodml_weekend
BEFORE
INSERT OR UPDATE OR DELETE ON EMP_TRG
BEGIN
IF TO_CHAR(sysdate, 'DY') IN ('토', '일') THEN
IF INSERTING THEN
raise_application_error(-20000, '주말 사원정보 추가 불가');
ELSIF UPDATING THEN
raise_application_error(-20001, '주말 사원정보 수정 불가');
ELSIF DELETING THEN
raise_application_error(-20002, '주말 사원정보 삭제 불가');
ELSE
raise_application_error(-20003, '주말 사원정보 변경 불가');
END IF;
END IF;
END;
/
UPDATE emp_trg SET sal = 3500 WHERE empno = 7788;
UPDATE emp_trg SET sal = 3500 WHERE empno = 7788;
CREATE TABLE EMP_TRG_LOG(
TABLENAME VARCHAR2(10), -- DML이 수행된 테이블 이름
DML_TYPE VARCHAR2(10), -- DML 명령어의 종류
EMPNO NUMBER(4), -- DML 대상이 된 사원 번호
USER_NAME VARCHAR2(30), -- DML을 수행한 USER 이름
CHANGE_DATE DATE -- DML이 수행된 날짜
);
CREATE OR REPLACE TRIGGER trg_emp_log
AFTER
INSERT OR UPDATE OR DELETE ON EMP_TRG
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO emp_trg_log
VALUES ('EMP_TRG', 'INSERT', :new.empno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
ELSIF UPDATING THEN
INSERT INTO emp_trg_log
VALUES ('EMP_TRG', 'UPDATE', :old.empno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
ELSIF DELETING THEN
INSERT INTO emp_trg_log
VALUES ('EMP_TRG', 'DELETE', :old.empno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
END IF;
END;
/
INSERT INTO EMP_TRG
VALUES(9999, 'TestEmp', 'CLERK', 7788,
TO_DATE('2018-03-03', 'YYYY-MM-DD'), 1200, null, 20);
COMMIT;
SELECT *
FROM EMP_TRG;
SELECT *
FROM EMP_TRG_LOG;
UPDATE EMP_TRG
SET SAL = 1300
WHERE MGR = 7788;
COMMIT;
SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT, TABLE_NAME, STATUS
FROM USER_TRIGGERS;
ALTER TRIGGER 트리거 이름 ENABLE | DISABLE
특정 테이블과 관련된 모든 트리거의 상태 활성화
ALTER TABLE 테이블 이름 ENABLE ALL TRIGGERS;
특정 테이블과 관련된 모든 트리거의 상태 비활성화
ALTER TABLE 테이블 이름 DISABLE ALL TRIGGERS;
DROP TRIGGER 트리거 이름;
Q1.
--①
CREATE OR REPLACE PROCEDURE pro_dept_in
(
inout_deptno IN OUT DEPT.DEPTNO%TYPE,
out_dname OUT DEPT.DNAME%TYPE,
out_loc OUT DEPT.LOC%TYPE
)
IS
BEGIN
SELECT DEPTNO, DNAME, LOC INTO inout_deptno, out_dname, out_loc
FROM DEPT
WHERE DEPTNO = inout_deptno;
END pro_dept_in;
/
--②
DECLARE
v_deptno DEPT.DEPTNO%TYPE;
v_dname DEPT.DNAME%TYPE;
v_loc DEPT.LOC%TYPE;
BEGIN
v_deptno := 10;
pro_dept_in(v_deptno, v_dname, v_loc);
DBMS_OUTPUT.PUT_LINE('부서번호 : ' || v_deptno);
DBMS_OUTPUT.PUT_LINE('부서명 : ' || v_dname);
DBMS_OUTPUT.PUT_LINE('지역 : ' || v_loc);
END;
/
Q2.
CREATE OR REPLACE FUNCTION func_date_kor(
in_date IN DATE
)
RETURN VARCHAR2
IS
BEGIN
RETURN (TO_CHAR(in_date, 'YYYY"년"MM"월"DD"일"'));
END func_date_kor;
/
Q3.
--①
CREATE TABLE DEPT_TRG
AS SELECT * FROM DEPT;
--②
CREATE TABLE DEPT_TRG_LOG(
TABLENAME VARCHAR2(10), -- DML이 수행된 테이블 이름
DML_TYPE VARCHAR2(10), -- DML 명령어의 종류
DEPTNO NUMBER(2), -- DML 대상이 된 부서번호
USER_NAME VARCHAR2(30), -- DML을 수행한 USER 이름
CHANGE_DATE DATE -- DML 이 수행된 날짜
);
--③
CREATE OR REPLACE TRIGGER trg_dept_log
AFTER
INSERT OR UPDATE OR DELETE ON DEPT_TRG
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO DEPT_TRG_LOG
VALUES ('DEPT_TRG', 'INSERT', :new.deptno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
ELSIF UPDATING THEN
INSERT INTO DEPT_TRG_LOG
VALUES ('DEPT_TRG', 'UPDATE', :old.deptno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
ELSIF DELETING THEN
INSERT INTO DEPT_TRG_LOG
VALUES ('DEPT_TRG', 'DELETE', :old.deptno,
SYS_CONTEXT('USERENV', 'SESSION_USER'), sysdate);
END IF;
END;
/