[ WITH순환절, CURSOR, 동적쿼리 ] 이용하여 1~100을 더하는 과정을 출력하는 예제를 만들어 보았다.
1. 예제 소스.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/** DBMS를 출력 **/
SET SERVEROUTPUT ON
/** 경과 시간을 출력 **/
SET TIMING ON
/**
* 1~100을 더하는 과정을 출력하시오.
*/
DECLARE
/** 계산용 변수 **/
V_START_NUM NUMBER;
V_END_NUM NUMBER;
V_ROWNUM NUMBER;
V_NUM NUMBER;
V_TOTAL NUMBER;
/** 결과처리용 변수 **/
V_RESULT VARCHAR2(4000);
/** 예외처리용 변수 **/
V_ERR_MSG VARCHAR2(4000);
E_END_POINT EXCEPTION;
E_IGNORE EXCEPTION;
/** 동적쿼리용 변수 **/
V_QRY VARCHAR2(4000);
/** 커서 **/
TYPE MY_CURSOR IS REF CURSOR;
CUR1 MY_CURSOR;
BEGIN
/** 변수 초기화 **/
V_START_NUM := 1;
V_END_NUM := 100;
V_NUM := 0;
V_TOTAL := 0;
V_RESULT := '';
V_ERR_MSG := '';
V_QRY := '';
BEGIN
/** WITH 순환절 && 동적쿼리 && CURSOR **/
V_QRY := '
WITH NUMBERS ( NUM ) AS (
SELECT :1 AS NUM
FROM DUAL
UNION ALL
SELECT A.NUM + 1 AS NUM
FROM NUMBERS A
WHERE A.NUM < :2
)
SELECT ROWNUM
, T1.NUM
FROM NUMBERS T1
';
/** 동적쿼리에 변수를 대입하고 CURSOR로 실행 **/
OPEN CUR1 FOR V_QRY USING V_START_NUM, V_END_NUM;
LOOP
/** CURSOR에서 조회된 COLUMN을 차례대로 변수에 저장 **/
FETCH CUR1 INTO V_ROWNUM, V_NUM;
/** 조회된 ROW가 없으면 LOOP를 탈출 **/
EXIT WHEN CUR1%NOTFOUND;
/** 1~100까지 더하는 과정 출력 **/
DBMS_OUTPUT.PUT_LINE( V_ROWNUM||' | '|| V_TOTAL||' + '||V_NUM||' = '||( V_TOTAL+V_NUM ) );
/** 집계 **/
V_TOTAL := V_TOTAL + V_NUM;
END LOOP;
CLOSE CUR1;
/** 집계가 100회 수행되었는지 확인 **/
--V_ROWNUM := 141;
IF V_ROWNUM != 100 THEN
/** 사용자정의 예외 발생 **/
RAISE E_END_POINT;
END IF;
/** 집계결과가 정상적인지 확인 **/
--V_TOTAL := 9999;
IF V_TOTAL != 5050 THEN
/** 사용자정의 예외 발생 **/
RAISE E_IGNORE;
END IF;
/** 결과 메시지 생성 **/
V_RESULT := '1~100을 모두 더한 값은 '||CHR(39)||V_TOTAL||CHR(39)||'입니다.';
/**
* 예외처리2
* 처리되지않은 오류는 상위블록의 EXCEPTION으로 전파됨.
**/
EXCEPTION
/** E_END_POINT EXCEPTION을 CATCH **/
WHEN E_END_POINT THEN
/** SQLCODE와 SQLERRM을 정의한 예외를 발생(상위 EXCEPTION으로 전파) **/
RAISE_APPLICATION_ERROR( -20001, '100회가 수행되지 않았습니다. [수행:'||V_ROWNUM||']' );
/** E_IGNORE EXCEPTION을 CATCH **/
WHEN E_IGNORE THEN
/** 결과값에 오류를 저장하고 정상진행 **/
V_RESULT := '결과값이 틀렸습니다. [예상:5050][실제:'||V_TOTAL||']';
END
;
/** 결과 출력 **/
DBMS_OUTPUT.PUT_LINE( '=================[정상종료]=================' );
DBMS_OUTPUT.PUT_LINE( V_RESULT );
/** 예외처리1 **/
EXCEPTION
/** 모든 EXCEPTION을 CATCH **/
WHEN OTHERS THEN
/** 오류메시지 생성 **/
V_ERR_MSG := 'SQLCODE='||SQLCODE||', MESSAGE='||SQLERRM;
/** 오류 출력 **/
DBMS_OUTPUT.PUT_LINE( '=================[오류]=================' );
DBMS_OUTPUT.PUT_LINE( V_ERR_MSG );
END
;
|
cs |
2. 실행 결과.
2-1. 정상.

- 예상했던 값이 출력되면서 정상 종료.
2-2. 'E_END_POINT' EXCEPTION 발생.

- 수행횟수가 예상했던 횟수가 아니면 오류를 발생하도록 하였으므로 오류로 종료.
2-3. 'E_IGNORE' EXCEPTION 발생.

- 결과값이 틀렸을 경우, 다음 단계를 정상적으로 수행하도록 하였으므로 정상 종료.
3. 마치며.
- 이렇게까지 사용할 일은 거의 없을테지만, PL/SQL을 이렇게도 사용할 수 있다는 것을 보여주기위해 만들어보았다.
- 예제에 나온 것들만 알아도 PL/SQL이나 PROCEDURE를 사용하는데 무리가 없을 것이라고 생각된다.
'DATABASE > ORACLE' 카테고리의 다른 글
[SQL] WITH문을 이용한 계층형쿼리 ( With. CONNECT BY절) (2) | 2020.01.23 |
---|---|
[SQL] WITH문 (2) | 2020.01.22 |
[PL/SQL] 무작정 시작하기 (5) - EXCEPTION 예외 (0) | 2020.01.16 |
[PL/SQL] 무작정 시작하기 (4) - CURSOR (0) | 2020.01.14 |
[PL/SQL] 무작성 시작하기 (3) - LOOP, WHILE 반복문 (0) | 2020.01.13 |
댓글