251112 TIL
2025. 11. 12. 17:34ㆍCourses/아이티윌 오라클 DBA 과정
문제
-- [문제16] 사원번호를 입력값으로 받아서 그 사원의 이름, 급여, 부서이름을 출력하는 프로시저를 생성하세요.
-- 단 100번 사원이 입력값으로 들어오면 프로그램은 종료 할 수 있도록 작성해주세요.
CREATE OR REPLACE PROCEDURE emp_proc(p_id IN number)
IS
TYPE rec_type IS RECORD(
name employees.last_name%type,
sal employees.salary%type,
dept_name departments.department_name%type
);
v_rec rec_type;
eos EXCEPTION;
BEGIN
IF p_id = 100 THEN
RAISE eos;
END IF;
SELECT e.last_name, e.salary, d.department_name
INTO v_rec
FROM hr.employees e, hr.departments d
WHERE e.department_id = d.department_id
AND employee_id = p_id;
dbms_output.put_line(v_rec.name || ' ' || v_rec.sal || ' ' || v_rec.dept_name);
EXCEPTION
WHEN eos THEN
null;
WHEN no_data_found THEN
dbms_output.put_line('데이터가 존재하지 않음');
WHEN others THEN
dbms_output.put_line(sqlcode);
dbms_output.put_line(sqlerrm);
END;
/
exec emp_proc(100); -- 종료
exec emp_proc(101); -- Kochhar 17000 Executive
exec emp_proc(300); -- 데이터가 존재하지 않음
컴파일 실패 시
SELECT text FROM user_source WHERE name = 'EMP_PROC' ORDER BY line;
SELECT * FROM user_objects WHERE object_name = 'EMP_PROC';

프로시저(Cont.)
RETURN
- 프로시저에서 값이 없는 RETURN문을 수행하면 프로그램은 정상 종료
CREATE OR REPLACE PROCEDURE emp_proc(p_id IN number)
IS
TYPE rec_type IS RECORD(
name employees.last_name%type,
sal employees.salary%type,
dept_name departments.department_name%type
);
v_rec rec_type;
BEGIN
IF p_id = 100 THEN
RETURN;
END IF;
SELECT e.last_name, e.salary, d.department_name
INTO v_rec
FROM hr.employees e, hr.departments d
WHERE e.department_id = d.department_id
AND employee_id = p_id;
dbms_output.put_line(v_rec.name || ' ' || v_rec.sal || ' ' || v_rec.dept_name);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('데이터가 존재하지 않음');
WHEN others THEN
dbms_output.put_line(sqlcode);
dbms_output.put_line(sqlerrm);
END;
/
- 익명 블록에서도 값이 없는 RETURN문을 수행하면 프로그램은 정상 종료
DECLARE
TYPE rec_type IS RECORD(
name employees.last_name%type,
sal employees.salary%type,
dept_name departments.department_name%type
);
v_rec rec_type;
BEGIN
IF :b_id = 100 THEN
RETURN;
END IF;
SELECT e.last_name, e.salary, d.department_name
INTO v_rec
FROM hr.employees e, hr.departments d
WHERE e.department_id = d.department_id
AND employee_id = :b_id;
dbms_output.put_line(v_rec.name || ' ' || v_rec.sal || ' ' || v_rec.dept_name);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('데이터가 존재하지 않음');
WHEN others THEN
dbms_output.put_line(sqlcode);
dbms_output.put_line(sqlerrm);
END;
/
IN OUT 모드
- 호출 환경에서 값을 프로시저로 전달하고, 동일한 파라미터를 사용하여 프로시저에서 값을 다시 호출 환경으로 전달
- 변수로 동작
- 실제 매개변수에 초기 값이 있는 변수 사용
-- format_phone 프로시저 생성
CREATE OR REPLACE PROCEDURE format_phone(p_no IN OUT varchar2)
IS
BEGIN
dbms_output.put_line(p_no);
p_no := substr(p_no, 1, 3) || '-' || substr(p_no, 4, 4) || '-' || substr(p_no, 8);
dbms_output.put_line(p_no);
END;
/
-- 프로시저 호출
var b_no varchar2(20);
exec :b_no := '01012345678';
exec format_phone(:b_no);
-- 익명 블록으로 format_phone 구현
var b_no varchar2(20)
exec :b_no := '01012345678'
print :b_no;
BEGIN
:b_no := substr(:b_no, 1, 3) || '-' || substr(:b_no, 4, 4) || '-' || substr(:b_no, 8);
END;
/
print :b_no;
실제 매개 변수 입력 방식
테이블 및 프로시저 생성
CREATE TABLE hr.sawon
(id number, name varchar2(30), day date, deptno number)
TABLESPACE users;
desc hr.sawon;
INSERT INTO hr.sawon (id, name, day, deptno) VALUES(입력변수, 입력변수, 입력변수, 입력변수);
CREATE OR REPLACE PROCEDURE sawon_insert
(p_id IN sawon.id%type,
p_name IN sawon.name%type,
p_day IN sawon.day%type default sysdate,
p_deptno IN sawon.deptno%type)
IS
BEGIN
INSERT INTO hr.sawon (id, name, day, deptno) VALUES(p_id, p_name, p_day, p_deptno);
END sawon_insert;
/
위치 지정 방식
-- 위치 지정 방식으로 입력
exec sawon_insert(1, 'oracle', sysdate, 10);
이름 지정 방식
-- 이름 지정 방식으로 입력
exec sawon_insert(p_id=>2, p_name=>'python', p_deptno=>20);
혼합 방식
-- 혼합 방식으로 입력
exec sawon_insert(3, 'java', p_deptno=>30);
exec sawon_insert(4, p_name=>'javascript', sysdate, 40); -- PLS-00312: a positional parameter association may not follow a named association
- 이름 지정 방식 뒤에 위치 지정 방식을 사용할 경우 오류 발생
프로시저 권한 부여
HR
-- anna 에게 sawon 권한 부여
GRANT select ON hr.sawon TO anna;
GRANT execute ON hr.sawon_insert TO anna;
SELECT * FROM user_tab_privs;
ANNA
SELECT * FROM user_tab_privs;

exec hr.sawon_insert(1, 'oracle', p_deptno=>10);
SELECT * FROM hr.sawon;

- insert 권한이 없지만 프로시저 실행 권한을 통해 간접적으로 insert 수행 가능
예외 처리 위치
테이블 및 권한 생성
DROP TABLE hr.emp PURGE;
DROP TABLE hr.dept PURGE;
CREATE TABLE hr.emp AS SELECT * FROM hr.employees;
CREATE TABLE hr.dept AS SELECT * FROM hr.departments;
ALTER TABLE hr.emp ADD CONSTRAINT empid_pk PRIMARY KEY(employee_id);
ALTER TABLE hr.dept ADD CONSTRAINT deptid_pk PRIMARY KEY(department_id);
ALTER TABLE hr.dept ADD CONSTRAINT dept_mgr_id_fk FOREIGN KEY(manager_id) REFERENCES hr.emp(employee_id);;
SELECT * FROM user_constraints WHERE table_name IN ('DEPT', 'EMP');
SELECT * FROM user_cons_columns WHERE table_name IN ('DEPT', 'EMP');
SELECT * FROM hr.emp;
SELECT * FROM hr.dept;
시나리오 1 : 예외 처리 X
-- 신규 부서 정보를 입력하는 프로시저
CREATE OR REPLACE PROCEDURE add_dept(p_name IN varchar2, p_mgr IN number, p_loc IN number)
IS
v_max number;
BEGIN
SELECT max(department_id)
INTO v_max
FROM hr.dept;
INSERT INTO hr.dept(department_id, department_name, manager_id, location_id)
VALUES(v_max + 10, p_name, p_mgr, p_loc);
END add_dept;
/
desc add_dept;
/*
PROCEDURE add_dept
인수 이름 유형 In/Out 기본값?
------ -------- ------ -------
P_NAME VARCHAR2 IN unknown
P_MGR NUMBER IN unknown
P_LOC NUMBER IN unknown
*/
exec add_dept('경영기획', 100, 1800);
exec add_dept('경영기획', 300, 1800); -- ORA-02291: integrity constraint (HR.DEPT_MGR_ID_FK) violated - parent key not found
BEGIN
add_dept('경영기획', 100, 1800);
add_dept('데이터아키텍처', 300, 1700);
add_dept('인재개발', 101, 1800);
END;
/
-- ORA-02291: integrity constraint (HR.DEPT_MGR_ID_FK) violated - parent key not found
- 프로그램 비정상 종료 → 자동 롤백
시나리오 2 : 호출하는 프로그램에서 Exception 처리
CREATE OR REPLACE PROCEDURE add_dept(p_name IN varchar2, p_mgr IN number, p_loc IN number)
IS
v_max number;
BEGIN
SELECT max(department_id)
INTO v_max
FROM hr.dept;
INSERT INTO hr.dept(department_id, department_name, manager_id, location_id)
VALUES(v_max + 10, p_name, p_mgr, p_loc);
END add_dept;
/
-- 호출하는 프로그램에서 exception 처리
BEGIN
add_dept('경영기획', 100, 1800);
add_dept('데이터아키텍처', 300, 1700);
add_dept('인재개발', 101, 1800);
EXCEPTION
WHEN others THEN
dbms_output.put_line(sqlerrm);
END;
/
SELECT * FROM hr.dept;
ROLLBACK;

add_dept('데이터아키텍처', 300, 1700);실행 시 예외가 발생하여 호출 프로그램이 종료되므로 이전 프로시저문까지만 처리됨 → 데이터아키턱처 입력 전에 입력한 경영기획 부서만 입력됨
시나리오3 : 프로시저에서 exception 처리
-- 프로시저에서 exception 처리
CREATE OR REPLACE PROCEDURE add_dept(p_name IN varchar2, p_mgr IN number, p_loc IN number)
IS
v_max number;
BEGIN
SELECT max(department_id)
INTO v_max
FROM hr.dept;
INSERT INTO hr.dept(department_id, department_name, manager_id, location_id)
VALUES(v_max + 10, p_name, p_mgr, p_loc);
EXCEPTION
WHEN others THEN
dbms_output.put_line(sqlerrm);
END add_dept;
/
BEGIN
add_dept('경영기획', 100, 1800);
add_dept('데이터아키텍처', 300, 1700);
add_dept('인재개발', 101, 1800);
END;
/
SELECT * FROM hr.dept;
ROLLBACK;

add_dept('데이터아키텍처', 300, 1700);실행 시 예외가 발생하여 프로시저가 종료되고 호출 프로그램에서 다음 프로시저문 실행 → 예외가 발생한 데이터아키텍처 부서만 입력 안됨
프로시저 삭제
-- 프로시저 삭제
DROP PROCEDURE add_dept;
함수(Functions)
- 값을 반환하는 이름이 있는 PL/SQL 블록
- 반복 실행을 위해 데이터베이스에 객체로 저장 가능
- 기능의 프로그램
- 표현식의 일부로 호출되거나 다른 서브 프로그램에서 호출 가능
- 형식 매개 변수는 IN 모드만 가능
- 함수를 생성하기 위해서
CREATE PROCEDURE권한 필요
CREATE OR REPLACE FUNCTION function_name
(parameter IN datatype, ...)
RETURN datatype
IS
변수, 상수, 명시적 커서, 사용자 정의 예외 사항
BEGIN
...
RETURN 값;
EXCEPTION
END function_name;
/
함수 생성 및 호출
프로시저로 구현
-- 프로시저로 구현
CREATE OR REPLACE PROCEDURE get_sal_proc
(p_id IN number, p_sal OUT number)
IS
BEGIN
SELECT salary
INTO p_sal
FROM hr.employees
WHERE employee_id = p_id;
EXCEPTION
WHEN no_data_found THEN
return;
END get_sal_proc;
/
desc get_sal_proc;
/*
PROCEDURE get_sal_proc
인수 이름 유형 In/Out 기본값?
----- ------ ------ -------
P_ID NUMBER IN unknown
P_SAL NUMBER OUT unknown
*/
-- 프로시저 호출
var b_sal number;
exec get_sal_proc(150, :b_sal);
exec get_sal_proc(300, :b_sal);
print :b_sal;
SELECT count(*) FROM hr.employees WHERE salary < :b_sal;
-- 익명 블록으로 프로시저 호출
DECLARE
v_sal number;
v_cnt number;
BEGIN
get_sal_proc(150, v_sal);
dbms_output.put_line(v_sal);
SELECT count(*)
INTO v_cnt
FROM hr.employees
WHERE salary < v_sal;
dbms_output.put_line(v_cnt);
END;
/
함수 사용
-- 함수 생성
CREATE OR REPLACE function get_sal_func
(p_id IN number)
RETURN number
IS
v_sal number;
BEGIN
SELECT salary
INTO v_sal
FROM hr.employees
WHERE employee_id = p_id;
RETURN v_sal;
EXCEPTION
WHEN no_data_found THEN
RETURN v_sal;
END get_sal_func;
/
desc get_sal_func;
/*
FUNCTION get_sal_func RETURNS NUMBER
인수 이름 유형 In/Out 기본값?
----- ------ ------ -------
P_ID NUMBER IN unknown
*/
-- 함수 호출
var b_sal number;
exec :b_sal := get_sal_func(100);
print b_sal;
exec dbms_output.put_line(get_sal_func(100));
-- 익명 블록으로 함수 호출
DECLARE
v_sal number;
BEGIN
v_sal := get_sal_func(100);
dbms_output.put_line(v_sal);
dbms_output.put_line(get_sal_func(100));
END;
/
- 함수는 표현식의 일부로 사용 가능
- 변수 값 할당 또는 다른 함수의 매개 변수 값으로 사용 가능
- SQL 안에서도 사용 가능
SELECT get_sal_func(employee_id) FROM hr.employees WHERE department_id = 20;

함수 삭제
-- 함수 삭제
DROP FUNCTION get_sal_func;'Courses > 아이티윌 오라클 DBA 과정' 카테고리의 다른 글
| 251114 TIL (0) | 2025.11.14 |
|---|---|
| 251113 TIL (0) | 2025.11.13 |
| 251111 TIL (0) | 2025.11.11 |
| 251110 TIL (0) | 2025.11.10 |
| 251107 TIL (0) | 2025.11.07 |