게시일: Nov 24, 2011 12:14:4 AM
- 패키지
: 오라클 데이터베이스에 저장된 프로시저, 함수 뿐만 아니라 변수, 상수, 커서, exception 들을 하나로 묶은 캡슐화된 객체
: 처리하는 작업의 성격이 비슷한 함수나 프로시저를 하나로 묶어 놓은 오라클 객체
예) execute 패키지명.오브젝트명(파라미터);
DBMS_OUTPUT.PUT_LINE 역시 패키지이다. DBMS_OUTPUT 패키지에 포함된 PUT_LINE 함수를 사용한 것이다.
ㅇ 패키지의 장점 (객체지향적 성격)
1. 애플리케이션을 좀 더 효율적으로 개발할 수 있게 도와준다. (모듈화)
2. 관련된 스키마 오브젝트들을 재 컴파일할 필요 없이 수정이 가능하다. (종속성)
: 패키지 내에 있는 하나의 함수의 내용이 변경될 경우 같은 패키지 내에서 이 함수를 호출하는 다른 함수나 프로시저들을 재컴파일 할 필요가 없다.
3. 한 번에 여러 개의 패키지 오브젝트들을 메모리에 로드할 수 있다.
4. 프로시저나 함수들의 오버로딩이 가능하다.
: 오버로딩 - 파라미터 개수가 다른 경우 동일한 이름을 가진 함수나 프로시저를 여러 개 선언해서 사용할 수 있다.
: 개별 함수나 프로시저를 선언할 경우에는 오버로딩할 수 없다.
5. 패키지 내의 모든 타입, 항목, 서브프로그램들을 PUBLIC 이나 PRIVATE 으로 선언해서 사용할 수 있다. (정보은닉)
- 패키지의 구조와 사용
: 패키지 명세부와 구현부 두 부분으로 구성
. 명세부에서 선언하는 이러한 객체들은 모두 PUBLIC 속성을 가진다. 즉 패키지 외부에서 접근이 가능하다.
. 구현부에서만 객체를 선언해서 사용할 수 있는데, 이러한 객체들은 패키지 내부에서만 참조 가능한 PRIVATE 속성을 가지게 된다.
-- 패키지 선언부
CREATE OR REPLACE PACKAGE employee_process AS
-- 타입, 커서, exception 선언 (PUBLIC 속성)
TYPE EmpRecord is RECORD (emp_id INT, salary REAL);
TYPE DeptRecord IS RECORD (dept_id INT, loc_id INT );
CURSOR salaries RETURN EmpRecord; -- 위에서 선언한 EmpRecord를 반환하는 커서 선언
invalid_salary EXCEPTION; -- 급여가 맞지 않을 경우 예외처리를 위한 exception 선언
-- 프로시저 선언
PROCEDURE hire_employee ( first_name VARCHAR2
, last_name VARCHAR2
, emails VARCHAR2
, job_id VARCHAR2
, mgr_id REAL
, salary REAL
, commission REAL
, dept_id REAL
);
PROCEDURE fire_employee ( emp_id INT );
PROCEDURE raise_salary ( emp_id INT
, j_id VARCHAR2
, amount REAL
);
-- 함수 선언
FUNCTION nth_highest_salary (n INT) RETURN EmpRecord;
FUNCTION sal_ok (j_id VARCHAR2, salary REAL) RETURN BOOLEAN;
END employee_process;
PACKAGE employee_process Compiled
-- 패키지 구현부
CREATE OR REPLACE PACKAGE BODY employee_process AS
-- 이 변수는 구현부에 선언되었으므로 PRIVATE 속성
number_hired INT;
-- 선언부에서 선언한 커서를 정의
CURSOR salaries RETURN EmpRecord IS
SELECT employee_id
, salary
FROM employees
ORDER BY salary DESC;
-- 신규사원 등록
PROCEDURE hire_employee ( first_name VARCHAR2
, last_name VARCHAR2
, emails VARCHAR2
, job_id VARCHAR2
, mgr_id REAL
, salary REAL
, commission REAL
, dept_id REAL
) IS
new_employee_id int;
BEGIN
SELECT employee_seq.NEXTVAL
INTO new_employee_id
FROM dual;
-- insert, 상세 컬럼 생략
INSERT INTO employee (....) VALUES (....);
number_hired := number_hired + 1;
END hire_employee;
-- 퇴사 처리
PROCEDURE fire_employee ( emp_id INT ) IS
BEGIN
-- delete, 상세 컬럼 생략
DELETE ....;
COMMIT;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Delete Error!!!');
ROLLBACK;
END fire_employee;
FUNCTION sal_ok (j_id VARCHAR2, salary REAL) RETURN BOOLEAN is
min_sal REAL;
max_sal REAL;
BEGIN
SELECT min_salary
, max_salary
FROM jobs
WHERE job_id = j_id;
-- 두 조건 모두 만족해야 true
RETURN ( (salary >= min_salary) AND (salary <= max_sal) );
END sal_ok;
PROCEDURE raise_salary ( emp_id INT
, j_id VARCHAR2
, amount REAL
) is
current_sal REAL;
BEGIN
SELECT salary
INTO current_sal
FROM employees
WHERE employee_id = emp_id;
-- 위의 sal_ok 함수 call
IF sal_ok(j_id, currnet_sal+amount) THEN
-- update, 상세 컬럼 생략
UPDATE ....;
ELSE
RAISE invalid_salary; -- 선언부에 정의되어 있음
END IF;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Success Upgrade');
EXCEPTION WHEN invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('Salaries Too High');
-- update가 실행되지 않았으므로 rollback 필요없음
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
ROLLBACK;
END raise_salary;
FUNCTION nth_highest_salary (n INT) RETURN EmpRecord IS
emp_rec EmpRecord;
BEGIN
OPEN salaries;
FOR i IN 1..n LOOP
FETCH salaries INTO emp_rec;
END LOOP;
CLOSE salaries;
RETURN emp_rec;
END nth_highest_salary;
BEGIN
number_hired := 0;
END employee_process;
-- 활용 예)
1) EXEC employee_process.hire_employee('aaa', 'bbb', 'ccc', 'ddd', 210, 5000, 0, 60);
commit;
2) EXEC employee_process.raise_salary('210', 'ddd', 6000); -- Salaries Too High
EXEC employee_process.raise_salary('210', 'ddd', 5000); -- Success Upgrade
3) DECLARE
-- employee_process 패키지에서 선언된 EmpRecord 레코드 타입의 변수 선언
test_emp employee_process.EmpRecord;
BEGIN
test_emp := employee_process.nth_highest_salary(1);
DBMS_OUTPUT.PUT_LINE('employee_id is : ' || test_emp.emp_id);
DBMS_OUTPUT.PUT_LINE('salary is : ' || test_emp.salary);
END;