FOR LOOP 문 기능 개선

2023. 5. 27.·Oracle/PLSQL

개요

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

 

저작자표시 비영리 변경금지 (새창열림)
'Oracle/PLSQL' 카테고리의 다른 글
  • 컬렉션 할당 기능 개선
  • Qualified Expression 기능 개선
  • UPDATE 문의 RETURNING INTO 절 개선
  • 단순 CASE 문 평가식 개선
정희락
정희락
2007년부터 Oracle Database 성능 최적화에 관심을 가져왔습니다. 현재 한국오라클 Engineered Systems Solution Engineering 팀에서 Solution Engineer로 근무하고 있습니다. 이 블로그는 개인적인 연구 목적으로 운영되며 Oracle 사의 공식적인 입장을 대변하지 않습니다.
  • 정희락
    TunA
    정희락
  • 전체
    오늘
    어제
    • 분류 전체보기 (201) N
      • Oracle (173) N
        • SQL (33)
        • PLSQL (10)
        • Performance (74)
        • Administration (37)
        • Installation (3)
        • Utilities (1)
        • JSON (8)
        • Vector (7) N
      • Exadata (15)
      • SQL*Plus (2)
      • Linux (5)
      • Resources (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 도서

    • 불친절한 SQL 프로그래밍
    • 불친절한 PL/SQL 프로그래밍
  • 링크

    • Connor McDonald
    • Frits Hoogland
    • Jonathan Lewis
    • Julian Dontcheff
    • Julian Dyke
    • Kun Sun
    • Maria Colgan
    • Martin Bach
    • Mike Dietrich
    • Tanel Poder
  • 공지사항

  • 인기 글

  • 태그

    12c
    19c
    21c
    23ai
    case study
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
정희락
FOR LOOP 문 기능 개선
상단으로

티스토리툴바