본문 바로가기
BackEnd/DB, SQL

SQL 24편: 저장 서브프로그램(프로시저, 함수, 패키지, 트리거)

by summer_light 2022. 1. 26.

PL/SQL로 작성한 내용을 단 한 번 실행하는 데 사용하는 경우는 익명 블록이라고 한다. 익명 블록은 오라클에 저장 되지 않기 때문에 다시 실행하려면 PL/SQL블록을 다시 작성하여 실행하여야 한다. 이런 불편함 때문에 필요한 것이 이름을 지정하여 오라클에 저장해두는 PL/SQL 프로그램인 '저장 서브프로그램'이다. 저장 서브프로그램은 저장할 때 한 번 컴파일을 하며, 공유하여 사용할 수 있고, 다른 응용 프로그램에서 호출도 가능하다. 

 

대표적인 구현 방식은 다음과 같다.

저장 프로시저 특정 처리 작업 수행을 위한 서브 프로그램. SQL문에서는 사용할 수 없다.
저장 함수 특정 연산을 거친 결과 값을 반환하는 서브프로그램. SQL문에서 사용할 수 있다.
패키지 저장 서브프로그램을 그룹화 하는데 사용한다.
트리거 특정 이벤트가 발생할 때 자동으로 연달아 수행할 기능을 구현하는 데 사용한다. 

 

 

 

 


1. 프로시저

1) 기본 형식

CREATE [OR REPLACE] PROCEDURE 프로시저이름

( 파라미터이름N 모드(기본값: IN) 자료형 [:= | DEFAULT 기본값],

...

)

IS | AS

선언부

BEGIN

실행부

EXCEPTION

예외 처리부

END [프로시저 이름];

 

* 모드

IN 호출할 때 값을 입력 받음(기본값)
OUT 호출할 때 값을 반환
IN OUT 호출할 때 값을 입력받은 후 실행 결과 값을 반환

 

2) 실행하기

기본 값이 지정되어 있는 파라미터는 호출할 때 값을 지정하지 않아도 기본 값이 지정된 채로 실행 가능하다. 그 외 기본값이 지정되어 있지 않은 파라미터는 모두 지정해주어야만 오류 없이 실행될 수 있다. 파라미터 이름에 직접 값을 대입하는 방식도 가능하다.  

ex) EXCUTE 프로시저이름(param1 => 1, param2 => 20);

 

 

SQL*PLUS로 실행하기

EXCUTE 프로시저이름( );

SET SERVEROUTPUT ON;
EXECUTE 프로시저이름( );

 

 

PL/SQL 블록에서 프로시저 실행하기

BEGIN
	프로시저이름( );
END;
/

 

 

3) 조회하기

USER_SOURCE 데이터 사전에서 조회

 

 

4) 삭제하기

DROP PROCEDUTRE 프로시저이름;

 

 

5) 오류 정보 확인하기 

서브 프로그램을 만들 때 발생한 오류는 SHOW ERRORS 명령어와 USER_ERRORS 데이터 사전을 조회하여 확인할 수 있다. 

 

SHOW ERRORS 명령어

가장 최근에 생성되거나 변경된 서브프로그램의 오류 정보를 출력

SHOW ERRORS;

SHOW ERR;

SHOW ERRORS 프로그램종류 프로그램이름;

SHOW ERR 프로그램종류 프로그램이름;

 

USER_ERROS 데이터 사전 조회

SELECT *
FROM USER_ERRORS
WHERE NAME = '프로그램이름';

 

 

 

 


2. 함수

프로시저와 함수의 차이

- 함수는 SQL문에서 직접 실행 가능

- 프로시저는 IN, OUT, IN OUT 모드를 모두 사용할 수 있지만, 함수는 IN 모드만 사용 가능

- 함수는 반드시 하나의 값만을 반환 해야 하고, OUT 모드의 파라미터를 사용하는 프로시저와는 달리 RETURN문을 통해 반환 

 

1) 함수 기본 형식

CREATE [OR REPLACE] FUNCTION 함수이름

(파라미터이름N 자료형N,

...

)

RETURN 자료형

IS | AS

선언부

BEGIN

실행부

RETURN (반환 값);

EXCEPTION

예외 처리부

END [함수 이름];

 

2) 함수 실행하기

SQL 문에서 실행하기

SELECT 함수이름()

FROM DUAL;

 

PL/SQL로 함수 실행하기

DECLARE

반환받을변수이름 자료형;

BEGIN

반환받을변수 := 함수이름( );

END;

/

 

3) 함수 삭제하기

DROP FUNCTION 함수이름;

 

 

 

 


3. 패키지 

연관성이 높은 프로시저, 함수 등 여러 PL/SQL 서브 프로그램을 하나의 논리 그룹으로 묶어 통합 관리하는 데 사용하는 객체이다. 

 

1) 패키지의 장점

- 모듈성: 잘 묶어둔다는 뜻. 패키지 사이의 상호 작용을 더 간편하고 명료하게 해 주는 역할

- 쉬운 설계: 패키지에 포함할 서브 프로그램은 완벽하게 완성되지 않아도 정의가 가능하기 때문에, 전체 소스 코드를 작성하기 전에 미리 패키지에 저장할 서브프로그램을 지정할 수 있으므로 설계가 쉬워질 수 있다.

- 정보 은닉: 패키지에 포함하는 서브 프로그램의 외부 노출 여부 또는 접근 여부를 지정 가능하다. 즉 보안을 강화할 수 있다.

- 기능성 향상: 서브 프로그램 외에 변수.커서.예외 등도 각 세션이 유지되는 동안 선언해서 공용으로 사용할 수 있다. 예를 들어 특정 커서 데이터는 세션이 종료되기 전까지 보존되므로 여러 서브프로그램에서 사용할 수 있다.

- 성능 향상: 패키지에 포함한 모든 서브프로그램들은 메모리에 한 번에 로딩되는데, 메모리에 로딩된 후의 호출은 디스크 I/O를 일으키지 않으므로 성능이 향상된다. 

 

2) 패키지의 구조

명세와 본문을 나누어 작성한다. 패키지 명세에 선언한 여러 객체는 패키지 내부 뿐 아니라 외부에서도 참조 가능

 

명세 : 패키지에 포함할 변수, 상수, 예외, 커서 와 PL/SQL 서브 프로그램을 선언하는 용도로 작성

본문 : 명세에 선언한 서브 프로그램 코드를 작성한다. 패키지 본문에만 존재하는 프로그램은 패키지 내부에서만 사용할 수 있다. 패키지 본문 이름은 패키지 명세 이름과 같게 지정해야 한다.  

 

패키지 명세 기본 형식

CREATE [OR REPLACE] PACKAGE 패키지 이름

IS | AS

선언부

END [패키지 이름];

 

패키지 본문 기본 형식

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;
/

 

 

3) 패키지 조회하기

USER_SOURCE 데이터 사전 조회

SELECT *
FROM USER_SOURCE
WEHRE TYPE='PACKAGE' AND NAME ='패키지이름';

 

DESC 명령어로 조회

DESC 패키지이름;

 

 

4) 패키지 사용하기 

패키지이름.객체이름;

 

 

5) 패키지 삭제하기

패키지 명세와 본문을 한 번에 삭제

DROP PACKAGE 패키지이름;

 

패키지의 본문만 삭제 

DROP PACKAGE BODY 패키지이름;

 

 

6) 서브프로그램 오버로드

사용하는 파라미터의 개수, 자료형, 순서가 다를 경우에 한해서는 같은 패키지 내에서 이름이 같은 서브프로그램을 정의할 수 있다. 단, 서브프로그램 종류가 같아야 오버로드가 가능하다. 

 

 

 

 


4. 트리거

특정 상황이나 동작 등의 이벤트가 발생할 경우에 자동으로 실행되는 기능을 정의하는 PL/SQL 서브 프로그램

- EX. 어떤 테이블의 데이터를 특정 사용자가 변경하려고 할 때 해당 데이터나 사용자 기록을 확인한다거나, 데이터를 변경하지 못하게 막도록 함

- EX. 데이터베이스가 가동하거나 종료할 때 데이터베이스 관리자 등 관련 업무자에게 메일을 보내는 기능 

 

기대 효과

1. 여러 작업을 수행하기 위해 PL/SQL문, 서브프로그램을 일일이 실행해야 하는 번거로움을 줄일 수 있음 

2. 제약조건 만으로 구현이 어려운 복잡한 데이터 규칙을 정할 수 있어 더 수준 높은 데이터 정의가 가능함

3. 데이터 변경과 관련된 일련의 정보를 기록해 둘 수 있으므로 여러 사용자가 공유하는 데이터 보안성과 안정성, 그리고 문제가 발생했을 때 대처 능력을 높일 수 있음

 

다만 무분별하게 사용할 경우 데이터 베이스 성능을 떨어뜨리는 원인이 될 수 있으므로 주의가 필요하다. 

 

트리거가 동작을 지정할 수 있는 이벤트

- DML: INSERT, UPDATE, DELETE

- DDL: CREATE, ALTER, DROP

- DB 동작: SERVERERROR, LOGON, LOGOFF, STARTUP, SHUTDOWN

 

트리거 종류

DML트리거 DML 명령어를 기점으로 동작
DDL트리거 DDL 명령어를 기점으로 동작
INSTEAD OF 트리거 VIEW에 사용하는 DML 명령어를 기점으로 동작
시스템 트리거 데이터 베이스, 스키마 이벤트로 동작
단순 트리거 특정 시점에 동작
- 특정 문장이 실행되기 전 시점
- 특정 문장이 실행된 후 시점
- 특정 문장이 행에 영향을 미치기 전 시점
- 특정 문장이 행에 영향을 준 후 시점
복합 트리거 단순 트리거의 여러 시점에 동작

 

 

1) DML 트리거

기본 형식

CREATE [OR REPLACE] TRIGGER 트리거이름

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;

 

트리거 예제 (BEFORE)

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;
/

 

트리거 예제 (AFTER)

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;
/

 

트리거 조회하기

USER_TRIGGERS 데이터 사전을 조회한다.

 

 

트리거 변경

ALTER TRIGGER 트리거이름 ENABLE | DISABLE;

 

 

특정 테이블과 관련된 모든 트리거의 상태를 활성화/비활성화 하기 

ALTER TABLE 테이블이름 ENABLE | DIABLE ALL TRIGGERS

 

 

트리거 삭제

DROP TRIGGER 트리거이름; 

댓글