프로시저를 사용하다보면 데이터를 하나의 로우씩 처리해야하는 경우가 있다. 이 경우에 커서를 사용하면 여러개의 로우를 처리할 수 있다.
속성명 | 설명 |
---|---|
SQL%FOUND | 결과 집합의 패치로우 수가 1개 이상이면 TRUE, 아니면 FALSE |
SQL%NOTFOUND | 결과 집합의 패치 로우 수가 0이면 TRUE, 아니면 FALSE |
SQL%ROWCOUNT | 영향 받은 결과 집합의 로우 수 반환, 없으면 0을 반환 |
SQL%ISOPEN | 묵시적 커서는 항상 FALSE를 반환 |
-- 커서 선언
CURSOR 커서명[(매개변수1, 매개변수2, ...)]
IS
SELECT 문장;
-- 커서 열기
OPEN 커서명 [(매개변수1, 매개변수2, ...)]
-- 패치 단계에서 커서 사용
LOOP
FETCH 커서명 INTO 변수1, 변수2, ...;
EXIT WHEN 커서명%NOTFOUND;
END LOOP;
-- 커서 닫기
CLOSE 커서명;
DECLARE
vs_emp_name employees.emp_name%TYPE;
CURSOR cur_emp_dep (cp_department_id employees.department_id%TYPE)
IS
SELECT emp_name
FROM employees
WHERE department_id = cp_department_id;
BEGIN
OPEN cur_emp_dep(90);
LOOP
FETCH cur_emp_dep INTO vs_emp_name;
EXIT WHEN cur_emp_dep%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(vs_emp_name);
END LOOP;
CLOSE cur_emp_dep;
END;
FOR 레코드 IN 커서명(매개변수1, 매개변수2, ...)
LOOP
처리문;
END LOOP;
--예제
DECLARE
CURSOR cur_emp_dep(cp_department_id employees.department_id%TYPE)
IS
SELECT emp_name
FROM employees
WHERE department_id = cp_department_id;
BEGIN
FOR emp_rec IN cur_emp_dep(100)
LOOP
DBMS_OUTPUT.PUT_LINE(emp_rec.emp_name);
END LOOP;
END;
TYPE 커서_타입명 IS REF CURSOR[ RETURN 반환 타입 ];
커서_변수명 커서_타입명;
DECLARE
-- 사원명을 받아오기 위한 변수 선언
vs_emp_name employees.emp_name%TYPE;
-- 약한 커서 타입 선언
TYPE emp_dep_curtype IS REF CURSOR;
-- 커서 변수 선언
emp_dep_curvar emp_dep_curtype;
BEGIN
-- 커서 변수를 사용한 커서 정의 및 오픈
OPEN emp_dep_curvar FOR SELECT emp_name
FROM employees
WHERE department_id = 90;
-- LOOP문
LOOP
-- 커서 변수를 사용해 결과 집합을 vs_emp_name 변수에 할당
FETCH emp_dep_curvar INTO vs_emp_name;
-- 더 이상 패치된 참조 로우가 없으면 LOOP 탈출(커서 변수를 이용한 커서 속성 참조)
EXIT WHEN emp_dep_curvar%NOTFOUND;
-- 사원명을 출력
DBMS_OUTPUT.PUT_LINE(vs_emp_name);
END LOOP;
END;
/
DECLARE
-- 사원명을 받아오기 위한 변수 선언
vs_emp_name employees.emp_name%TYPE;
-- SYS_REFCURSOR 타입의 커서 변수 선언
emp_dep_curvar SYS_REFCURSOR;
BEGIN
-- 커서 변수를 사용한 커서 정의 및 오픈
OPEN emp_dep_curvar FOR SELECT emp_name
FROM employees
WHERE department_id = 100;
-- LOOP문
LOOP
-- 커서 변수를 사용해 결과 집합을 vs_emp_name 변수에 할당
FETCH emp_dep_curvar INTO vs_emp_name;
-- 더 이상 패치된 참조 로우가 없으면 LOOP 탈출(커서 변수를 이용한 커서 속성 참조)
EXIT WHEN emp_dep_curvar%NOTFOUND;
-- 사원명을 출력
DBMS_OUTPUT.PUT_LINE(vs_emp_name);
END LOOP;
END;
커서 표현식은 select문에서 컬럼으로 커서를 사용하는 것
-- 커서는 항상 한개의 로우를 반환할 수밖에 없음
SELECT d.department_name,
CURSOR (
SELECT e.emp_name
FROM employees e
WHERE e.department_id = d.department_id) AS emp_name
FROM departments d
WHERE d.department_id = 90;
데이터 타입의 변수는 한 번에 하나의 값만 설정하지만, 레코드와 컬렉션을 이용하면 여러개의 값을 설정하여 사용할 수 있다. (데이터 집합, 배열?과 같은 개념인거 같음)
TYPE 레코드명 IS RECORD(
필드명1 필드1 타입 [[NOT NULL] := 디폴트값],
필드명2 필드2 타입 [[NOT NULL] := 디폴트값],
);
레코드변수명 레코드명;
DECLARE
-- 부서 레코드 타입
TYPE depart_rect IS RECORD(
department_id departments.department_id%TYPE,
department_name departments.department_name%TYPE
);
vr_dep depart_rect;
vr_dep2 depart_rect;
BEGIN
vr_dep.department_id := 000;
vr_dep.department_name := '레코드 테스트 부서';
vr_dep2 := vr_dep;
DBMS_OUTPUT.PUT_LINE( 'vr_dep2.department_id :' || vr_dep2.department_id);
DBMS_OUTPUT.PUT_LINE( 'vr_dep2.department_name :' || vr_dep2.department_name);
END;
-- 레코드 필드 순서와 개수, 타입이 같다면 레코드 변수명으로만 insert가능
DECLARE
TYPE depart_rect IS RECORD(
department_id departments.department_id%TYPE,
department_name departments.department_name%TYPE
);
vr_dep depart_rect;
BEGIN
vr_dep.department_id := 9999;
vr_dep.department_name := '테스트';
-- insert into ch10_departments values (vr_dep.department_id, vr_dep.department_name);
insert into ch10_departments values vr_dep;
COMMIT;
END;
/
select * from ch10_departments;
-- 특정 테이블의 컬럼 값을 받아오는 변수를 선언할 때, 다음과 같이 선언하면 굳이 해당 컬럼의 데이터타입을 찾을 필요 없음
변수명 테이블명.컬럼명%TYPE;
-- 아래와 같이 하면 테이블 전체 데이터 타입을 레코드의 데이터 타입으로 주입가능
레코드 변수명 테이블명%ROWTYPE;
-- 예제
CREATE TABLE ch11_dep2 AS
SELECT *
FROM DEPARTMENTS;
TRUNCATE TABLE ch11_dep2;
select * from ch11_dep2;
DECLARE
vr_dep departments%ROWTYPE;
BEGIN
SELECT *
INTO vr_dep
FROM departments
WHERE department_id = 20;
INSERT INTO ch11_dep2 VALUES vr_dep;
COMMIT;
END;
/
SELECT * FROM CH11_DEP2;
-- 예제
create table ch11_dep as
select department_id, department_name
from departments;
truncate TABLE ch11_dep;
DECLARE
CURSOR c1 IS
SELECT department_id, department_name
FROM departments;
-- 커서형 레코드 변수 선언
vr_dep c1%ROWTYPE;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO vr_dep;
EXIT WHEN c1%NOTFOUND;
INSERT INTO ch11_dep VALUES vr_dep;
END LOOP;
COMMIT;
END;
/
SELECT * FROM ch11_dep;
-- 레코드 변수만 기술해서 타입이 같다면 열 전체 업데이트
DECLARE
vr_dep ch11_dep%ROWTYPE;
BEGIN
vr_dep.department_id := 60;
vr_dep.department_name := '테스트';
UPDATE ch11_dep
SET ROW = vr_dep
WHERE department_id = vr_dep.department_id;
COMMIT;
END;
/
select * from ch11_dep;
하나의 종류의 데이터 타입이 여러 개 붙어 있는 데이터 타입 (배열)
TYPE 연관_배열명 IS TABLE OF 연관_배열_값타입 INDEX BY 인덱스타입;