개요
Oracle 21c에서 FOR LOOP 문의 기능이 대폭 개선되었습니다.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다.
-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 (c1 NUMBER, c2 VARCHAR2(1));
INSERT INTO t1 VALUES (2, 'A');
INSERT INTO t1 VALUES (4, 'B');
INSERT INTO t1 VALUES (6, 'C');
COMMIT;
Iterand
FOR LOOP 문의 iterand에 MUTABLE 키워드와 constrained type을 사용할 수 있습니다.
pls_identifier [ MUTABLE | IMMUTABLE ] [constrained_type]
아래 예제는 iterand에 MUTABLE 키워드를 사용하여 루프 내에서 iterand를 변경합니다. MUTABLE 키워드를 사용하지 않으면 "PLS-00363: 'I' 식은 피할당자로 사용될 수 없습니다." 에러가 발생합니다. 참고로 루프 내에서 iterand를 변경하면 성능 저하나 무한 루프가 발생할 수 있습니다.
-- 2
BEGIN
FOR i MUTABLE IN 1 .. 10 LOOP
DBMS_OUTPUT.PUT_LINE (i);
i := i * 2;
END LOOP;
END;
/
1
3
7
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 하한 값과 상한 값에 소수 값, iterand에 constrained type을 사용합니다. 결과가 소수 값으로 표시됩니다. iterand에 constrained type을 사용하지 않으면 반올림된 정수 값이 표시됩니다.
-- 3
BEGIN
FOR i NUMBER(2,1) IN 1.5 .. 3.5 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1.5
2.5
3.5
PL/SQL 처리가 정상적으로 완료되었습니다.
Iteration Control
PL/SQL Language Reference는 FOR LOOP 문의 Iteration Control를 아래와 같이 구분합니다. 쉼표(,)로 구분해 다수의 Iteration Control을 사용할 수 있습니다.
iteration_control
stepped_control
single_expression_control
collection_iteration_control
values_of_control
indices_of_control
pairs_of_control
cursor_iteration_control
sql_statement
cursor_object
cursor_variable
dynamic_sql
Stepped Control
Stepped Control은 하한 값과 상한 값을 지정합니다. 21c부터 하한 값과 상한 값을 소수 값으로 지정할 수 있으며, BY 키워드로 증분 값을 지정할 수 있습니다.
[REVERSE] lower_bound .. upper_bound [BY step]
아래 예제는 BY 키워드를 사용하여 값을 2씩 증가시킵니다.
-- 4
BEGIN
FOR i IN 1 .. 10 BY 2 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
3
5
7
9
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 constrained type와 BY 키워드를 사용하여 값을 0.2씩 증가시킵니다.
-- 5
BEGIN
FOR i NUMBER(2,1) IN 1.0 .. 2.0 BY 0.2 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
1.2
1.4
1.6
1.8
2
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 FOR LOOP 문에 2개의 Iteration Control을 사용합니다.
-- 6
BEGIN
FOR i IN 1 .. 3, REVERSE 2 .. 6 BY 2 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
2
3
2
4
6
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 두 번째 Iteration Control의 하한 값과 상한 값에 iterand에 대한 산술 표현식을 사용합니다. 참고로 첫 번째 Iteration Control은 iterand를 참조할 수 없습니다.
-- 7
BEGIN
FOR i IN 1 .. 3, i + 4 .. i + 6 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
2
3
7
8
9
PL/SQL 처리가 정상적으로 완료되었습니다.
Single Expression Control
Single Expression Control은 단일 표현식과 반복 표현식으로 사용할 수 있습니다.
[REPEAT] expr
아래 예제는 다수의 단일 표현식을 사용합니다.
-- 8
BEGIN
FOR i IN 1, 3, 5, 7, 9 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
3
5
7
9
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 두 번째 Iteration Control에 반복 표현식을 사용합니다. 반복 표현식은 WHILE 절로 시작하는 Stopping 조건을 함께 사용해야 합니다.
-- 9
BEGIN
FOR i IN 1, REPEAT i * 2 WHILE i <= 16 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
2
4
8
16
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 WHEN 절로 시작하는 Skipping 조건을 사용합니다. 참고로 Stopping 조건과 Skipping 조건은 모든 Iteration Control에 사용할 수 있습니다.
-- 10
BEGIN
FOR i IN 1, REPEAT i * 2 WHILE i <= 16 WHEN i >= 8 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
1
8
16
PL/SQL 처리가 정상적으로 완료되었습니다.
Collection Iteration Control
아래 예제는 Values of Control로 연관 배열의 값을 조회합니다.
-- 11: values of control
DECLARE
TYPE taa IS TABLE OF VARCHAR2(1) INDEX BY PLS_INTEGER;
v1 taa := taa (2 => 'A', 4 => 'B', 6 => 'C');
BEGIN
FOR v IN VALUES OF v1 LOOP
DBMS_OUTPUT.PUT_LINE (v);
END LOOP;
END;
/
A
B
C
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 Indices of Control로 연관 배열의 인덱스를 조회합니다.
-- 12: indices of control
DECLARE
TYPE taa IS TABLE OF VARCHAR2(1) INDEX BY PLS_INTEGER;
v1 taa := taa (2 => 'A', 4 => 'B', 6 => 'C');
BEGIN
FOR i IN INDICES OF v1 LOOP
DBMS_OUTPUT.PUT_LINE (i);
END LOOP;
END;
/
2
4
6
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 Pairs of Control로 중첩 테이블의 인덱스(i)와 값(v)을 조회합니다.
-- 13: pairs of control
DECLARE
TYPE taa IS TABLE OF VARCHAR2(1) INDEX BY PLS_INTEGER;
v1 taa := taa (2 => 'A', 4 => 'B', 6 => 'C');
BEGIN
FOR i, v IN PAIRS OF v1 LOOP
DBMS_OUTPUT.PUT_LINE (i || ',' || v);
END LOOP;
END;
/
2,A
4,B
6,C
PL/SQL 처리가 정상적으로 완료되었습니다.
Cursor Iteration Control
아래 예제는 Iteration Control에 SQL 문을 사용합니다. 참고로 Cursor Iteration Control은 Collection Iteration Control과 동일하게 Values of, Indices of, Pairs of Coltrol을 사용할 수 있습니다.
-- 14: sql statement
BEGIN
FOR v IN (SELECT * FROM t1) LOOP
-- FOR v IN VALUES OF (SELECT * FROM t1) LOOP
DBMS_OUTPUT.PUT_LINE (v.c1 || ',' || v.c2);
END LOOP;
END;
/
2,A
4,B
6,C
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 Iteration Control에 커서 오브젝트를 사용합니다.
-- 15: cursor object
DECLARE
CURSOR cur1 IS SELECT * FROM t1;
BEGIN
FOR i, v IN PAIRS OF cur1 LOOP
DBMS_OUTPUT.PUT_LINE (i || ',' || v.c1 || ',' || v.c2);
END LOOP;
END;
/
1,2,A
2,4,B
3,6,C
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 Iteration Control에 커서 변수를 사용합니다.
-- 16: cursor variable
DECLARE
v1 SYS_REFCURSOR;
BEGIN
OPEN v1 FOR SELECT * FROM t1;
FOR i, v t1%ROWTYPE IN PAIRS OF v1 LOOP
DBMS_OUTPUT.PUT_LINE (i || ',' || v.c1 || ',' || v.c2);
END LOOP;
CLOSE v1;
END;
/
1,2,A
2,4,B
3,6,C
PL/SQL 처리가 정상적으로 완료되었습니다.
아래 예제는 Iteration Control에 동적 SQL 문을 사용합니다.
-- 17: dynamic sql
DECLARE
v_sql_text VARCHAR2(4000) := 'SELECT * FROM T1';
BEGIN
FOR i, v t1%ROWTYPE IN PAIRS OF (EXECUTE IMMEDIATE v_sql_text) LOOP
DBMS_OUTPUT.PUT_LINE (i || ',' || v.c1 || ',' || v.c2);
END LOOP;
END;
/
1,2,A
2,4,B
3,6,C
PL/SQL 처리가 정상적으로 완료되었습니다.
관련 링크
- PL/SQL Language Reference - FOR LOOP Statement Overview
- PL/SQL Language Reference - FOR LOOP Statement
- ORABLE-BASE - FOR LOOP Iteration Enhancements in Oracle Database 21c