21c NF - PL/SQL Extended Iteration 2
연관글
21c NF - PL/SQL Extended Iteration 1
이전 글에 이어 다 확인하지 못한 사항에 대해 더 확인해보도록 하겠다.
1. Mutable Iteration Variables
3. Qualified Expression 방식으로 FOR .. LOOP 간단히 표시해 보기
0. 테스트 데이터 생성
CREATE TABLE TEST_CUR_ITER
(
ID NUMBER,
NAME VARCHAR2(30)
);
INSERT INTO TEST_CUR_ITER VALUES('101','James');
INSERT INTO TEST_CUR_ITER VALUES('102','Scarlett');
INSERT INTO TEST_CUR_ITER VALUES('103','Michael');
INSERT INTO TEST_CUR_ITER VALUES('104','Andrew');
INSERT INTO TEST_CUR_ITER VALUES('105','Paul');
COMMIT;
|
cs |
1. Mutable Iteration Variables
Mutable 키워드를 통해 Loop 내에서 Iterand를 변경할 수 있도록 해 준다.
아래의 테스트 내용을 살펴보도록 하자.
Iterand가 수정이 안되는 부분을 보도록 하겠다.
19c 테스트 결과
BEGIN
FOR i in 1 .. 20 loop
DBMS_OUTPUT.PUT_LINE('i : ' || i);
i := i+4;
END LOOP;
END;
/
ORA-06550: line 4, column 3: PLS-00363: expression 'I' cannot be used as an assignment target ORA-06550: line 4, column 3: PL/SQL: Statement ignored
|
cs |
21c 테스트 결과
BEGIN
FOR i in 1 .. 20 loop
DBMS_OUTPUT.PUT_LINE('i : ' || i);
i := i+4;
END LOOP;
END;
/
ORA-06550: line 4, column 3: PLS-00363: expression 'I' cannot be used as an assignment target ORA-06550: line 4, column 3: PL/SQL: Statement ignored
|
cs |
19c와 같이 에러가 발생한다.
즉 i 라는 iterand 를 Loop 내에서 수정할 경우 에러가 발생하며 수정을 할 수 없다.
하지만 아래와 같이 mutable 이란 키워드를 사용해 보도록 하자.
BEGIN
FOR i MUTABLE in 1 .. 20 loop
DBMS_OUTPUT.PUT_LINE('i : ' || i);
i := i+4;
END LOOP;
END;
/
i : 1
i : 6
i : 11
i : 16
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.009
|
cs |
위와 같이 에러 없이 수행되는 것을 확인할 수 있다.
mutable 키워드는 21c 버전부터 지원된다.
for 뒤에 사용하는 루프 인덱스 역할의 iterand 값이 기존에는 immutable 성격이였다.
loop내의 로직에서 변경시 ORA-06550 에러를 만나게 된다.
하지만 21c에서 mutable 키워드를 사용할 경우 immutable 특성이 mutable로 변경된다.
주의할 점은 iterand를 수정할 경우 for loop 문장이 무한루프에 빠지지 않도록 유의하면서 코드를 작성해야 한다는 점이다.
2. Cursor Iteration Control
문법구조
cursor_iteration__control ::= { cursor _object
| sql_statement
| cursor_variable
| dynamic_sql }
|
cs |
cursor iteration control은 1번 글의 collection iteration의 VALUES OF와 같은 의미로 보인다.
REVERSE 키워드와는 같이 사용할 수 없다.
1) CURSOR를 사용한 Collection Iteration 중 VALUES 방법
BEGIN
FOR CUR IN VALUES OF (SELECT NAME
FROM TEST_CUR_ITER)
LOOP
DBMS_OUTPUT.PUT_LINE(CUR.NAME);
END LOOP;
END;
/
James
Scarlett
Michael
Andrew
Paul
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.012
|
cs |
2) CURSOR를 사용한 Collection Iteration 중 INDICES 방법
BEGIN
FOR IND IN INDICES OF (SELECT ID, NAME
FROM TEST_CUR_ITER)
LOOP
DBMS_OUTPUT.PUT_LINE(IND);
END LOOP;
END;
/
1
2
3
4
5
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.007
|
cs |
3) CURSOR를 사용한 Collection Iteration 중 PAIRS 방법
BEGIN
FOR IND, CUR IN PAIRS OF (SELECT ID, NAME
FROM TEST_CUR_ITER)
LOOP
DBMS_OUTPUT.PUT_LINE('INDEX : ' || IND || ' ID : ' || CUR.ID || ', NAME : ' || CUR.NAME);
END LOOP;
END;
/
INDEX : 1 ID : 101, NAME : James
INDEX : 2 ID : 102, NAME : Scarlett
INDEX : 3 ID : 103, NAME : Michael
INDEX : 4 ID : 104, NAME : Andrew
INDEX : 5 ID : 105, NAME : Paul
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.011
|
cs |
4) Dynamic SQL을 사용한 CURSOR 사용 방법
VALUES OF / INDICES OF / PAIRS OF 방법
DECLARE
SQL_STMT VARCHAR2(100) := 'SELECT NAME FROM TEST_CUR_ITER';
BEGIN
FOR VAL VARCHAR2(100) IN VALUES OF (EXECUTE IMMEDIATE SQL_STMT)
LOOP
DBMS_OUTPUT.PUT_LINE(VAL);
END LOOP;
END;
/
James
Scarlett
Michael
Andrew
Paul
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.010
|
cs |
DECLARE
SQL_STMT VARCHAR2(100) := 'SELECT ID FROM TEST_CUR_ITER';
BEGIN
FOR IND, VAL_ID NUMBER IN PAIRS OF (EXECUTE IMMEDIATE SQL_STMT)
LOOP
DBMS_OUTPUT.PUT_LINE('INDEX : ' || IND || ' ID : ' || VAL_ID);
END LOOP;
END;
/
INDEX : 1 ID : 101
INDEX : 2 ID : 102
INDEX : 3 ID : 103
INDEX : 4 ID : 104
INDEX : 5 ID : 105
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.009
|
cs |
DECLARE
SQL_STMT VARCHAR2(100) := 'SELECT ID, NAME FROM TEST_CUR_ITER';
TYPE REC IS RECORD(ID NUMBER, NAME VARCHAR2(30));
BEGIN
FOR IND, CUR REC IN PAIRS OF (EXECUTE IMMEDIATE SQL_STMT)
LOOP
DBMS_OUTPUT.PUT_LINE('INDEX : ' || IND || ', ID : ' || CUR.ID || ', NAME : ' || CUR.NAME);
END LOOP;
END;
/
INDEX : 1, ID : 101, NAME : James
INDEX : 2, ID : 102, NAME : Scarlett
INDEX : 3, ID : 103, NAME : Michael
INDEX : 4, ID : 104, NAME : Andrew
INDEX : 5, ID : 105, NAME : Paul
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.009
|
cs |
EXECUTE IMMEDIATE 방식을 사용할 경우 Return 값들의 데이터 타입이 컴파일 시점에 확인이 불가능하여
Iterand의 데이터 값이 명시적으로 맞아야 에러 없이 수행되는 듯하다.
3. Qualified Expression 방식으로 FOR .. LOOP 간단히 표시해 보기
Qualified Expression을 사용하지 않은 방법
DECLARE
TYPE TEST_T IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
TT TEST_T := TEST_T(10,20,30,40,50,60,70,80,90,100);
NEWTEST_T TEST_T;
BEGIN
FOR I IN 1..10 BY 2 LOOP
NEWTEST_T(i) := TT(i);
END LOOP;
FOR I,J IN PAIRS OF NEWTEST_T LOOP
DBMS_OUTPUT.PUT_LINE(I || '=>'|| J);
END LOOP;
END;
/
1=>10
3=>30
5=>50
7=>70
9=>90
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.006
|
cs |
아래는 Qualified Expression의 표현법으로 변경한 코드이다.
DECLARE
TYPE TEST_T IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
TT TEST_T := TEST_T(10,20,30,40,50,60,70,80,90,100);
NEWTEST_T TEST_T;
BEGIN
NEWTEST_T := TEST_T(FOR I IN 1..10 BY 2 => TT(i));
FOR I,J IN PAIRS OF NEWTEST_T LOOP
DBMS_OUTPUT.PUT_LINE(I || '=>'|| J);
END LOOP;
END;
/
1=>10
3=>30
5=>50
7=>70
9=>90
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.012
|
cs |
즉
FOR I IN 1..10 BY 2 LOOP
NEWTEST_T(i) := TT(i);
END LOOP;
|
cs |
위 부분이 아래와 같이 변경될 수 있다.
NEWTEST_T := TEST_T(FOR I IN 1..10 BY 2 => TT(i));
|
cs |
컬렉션에 데이터를 입력하는 방법이 수월해 질 수 있다.
활용 방법에 대해서는 더 많은 상황에 대해서 경험을 해봐야 알 거 같다.
4. Summary
2개의 게시글로 21c 버전에서 확장된 PL/SQL Iteration 사용예를 확인하며 New Feature 부분을 살펴보았다.
새로운 기능에 대해서 기능적인 측면에서 확인해 본 상태일 뿐이지 활용도 측면에서는 겉핡기 식인 내용 뿐이다.
내게있어서 이런 부분은 경험이나 상황을 통해서 활용도를 늘려나갈 수 있는 부분이라서 아직까지는 한계가 있는 듯하다.
이런 부분은 염두하고 글을 읽어 주었으면 한다.
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
» | 21c NF - PL/SQL Extended Iteration 2 | 명품관 | 2021.02.04 | 587 |
1 | 21c NF - PL/SQL Extended Iteration 1 | 명품관 | 2021.01.28 | 745 |