[질문] 커서의 사용법, 커서형의 반환법등... 0 22 9,068

by 손님 커서 프로시져 패키지 예외처리 EXCEPTION [2008.05.13 14:04:26]


된장님이 답변해 주셨는데.. 다른문제가 더 있는거 같아서요..

먼저 이전 질문 내용입니다.

===========================================================================

끙.. 이건 또 무슨 에러인지? ㅠ.ㅠ

ORA-01023: 커서 문맥이 없습니다(부적합한 커서번호).

어디를 찾아봐도 이런 에러가 있다라고는 되어 있는데 무슨 에러인지는 없네요...
프로시져를 만들어서 프로시져내에서 커서를 사용합니다.
에러 없이 만들어 졌는데 프로그램에서 사용하려고 실행하니 이런 에러를 리턴하네요.
유형에 따라 Select가 달라서 내부에 GOTO를 써서 커서를 사용하지 않을 수도 있습니다.
이거 때문일까요??

IS에 CURSOR CUR_AGTITINS IS 식으로 사용할 커서를 선언했고..

BEGIN
 FOR CUR_AGTITIN IN CUR_AGTITINS LOOP
  .
  .
  .
 END LOOP;
 EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLERRM||’에러발생’);
END;

 
식으로 본문에서 사용했습니다.
Oracle 초보임을 감안하셔서 자세히 설명해 주시면 감사하겠습니다.
위에 프로시져라고 했는데.. 패키지 입니다.. 요기서 리턴을 select형으로 하려고 cursor를 사용하는데..
이때문일까요????

======================= 여기까지가 저번 질문 이었습니다 =======================

된장님의 답변에 따르면 제가 사용한데 명시적 커서라는 말씀이신데..
가르쳐 주신데로 묵시적 커서로 변경하였습니다. (LOOP 문은 된장님이 빼먹으신거지요? ^^)
그래도 같은 에러가 발생하는데.. 혹.. 저 커서의 결과가 없으면 나오는 에러 일까요???
그렇다면 예외 처리를 어찌 하면 될까요?

그리고.. 저 커서 부분을 몽땅 주석 처리하고 해도 같은 에러가 나오는데..
제가 결과 반환 방법을 커서로 반환해서 그런듯 싶은데.. 역시 결과가 있으면 되는거 같고..
결과가 없으면 에러가 나는듯 싶습니다.

Record 의 수가 0로 반환하려면 어찌 하면 되지요??
모듈에서는 Record의 수는 체크 하거든요..

제가 사용한 커서 반환은 이런식으로 했습니다

PROCEDURE TEST_PRC(
 o_cur  OUT t_cur
)
IS
 p_cur    t_cur;
BEGIN
 OPEN p_cur FOR
  SELECT *
  FROM TEST_TBL
  WHERE IDX = i_IDX;

 o_cur := p_cur;
END TEST_PRC;

제가 사용한 방식에서 결과가 없다면 에러 나는듯 싶은데.. 예외 처리를 어찌 하면 좋죠?

질문 정리...

1. 명시적, 묵시적 커서 사용시의 결과 없음의 예외 처리법
2. 커서형의 Record반환시 결과 없음의 반환 (Record 0 라고 반환할 수 있는방법)
3. 위의 제가 사용한 커서형 반환시 결과가 존재하지 않을때 예외 처리법

고수님들.. 가르쳐 주시면 복받으실꺼에요~~~

======================= 된장님의 답변입니다 ============================

- 된장  [2008-05-08 15:19]  
 
Oracle Reference에 있는 예제를 그대로 올릴께요.
-------묵시적 Cursor---------
임의로 커서를 선언하지 않고 사용.
BEGIN
 FOR item IN ( SELECT last_name, job_id
   FROM employees
   WHERE job_id LIKE ’%CLERK%’
    AND manager_id > 120 )
 DBMS_OUTPUT.PUT_LINE
  (’Name = ’ || item.last_name || ’, Job = ’ || item.job_id);
 END LOOP;
END;
/

----명시적 Cursor 선언-----------------
DECLARE
 CURSOR c1 IS SELECT last_name, job_id FROM employees
   WHERE job_id LIKE ’%CLERK%’ AND manager_id > 120;
BEGIN
 FOR item IN c1
 LOOP
  DBMS_OUTPUT.PUT_LINE
   (’Name = ’ || item.last_name || ’, Job = ’ || item.job_id);
 END LOOP;
END;
/

한번 보시면 아실 수 있을 꺼에염..~~..

by 된장 [2008.05.13 14:34:30]
전에 설명한 기억두 없는뎅.ㅠㅠ
헐.적은거 네트웍 장애나면서 날아갔네염..
우선은 에러 넘버
ORA-01023 Cursor context not found (Invalid cursor number)
Cause: The cursor number is not a valid open cursor.
Action: Make sure that the cursor is open.
일단 커서가 열려있지 않다는 거구염..
-------------------------
실력이없어서 위에 문제가 있는것은 파악을 못하겠구요
다만 1,2,3에 대한 답은 할 수 있졍..
1.EXIT WHEN 커서명%NOTFOUND; --루프내에 삽입하면 될 것 같은데염.
2,3번 합
EXCEPTION --Exception처리
WHEN NO_DATA_FOUND THEN
리턴되는 o_cur =0; --요렇게 하면 될 것 같은데염.
END;

Exception Oracle Error SQLCOD
ACCESS_INTO_NULL ORA-06530 -6530
CASE_NOT_FOUND ORA-06592 -6592
COLLECTION_IS_NULL ORA-06531 -6531
CURSOR_ALREADY_OPEN ORA-06511 -6511
이외에도...규정된 에러값이 많아요..지면관계상..ㅋ.ㅋ.
제가 DB를 않쓰는 일을 해서리 자세히는 모릅니당.
걍 취미로 올리니까..참고하실 분만..보세염..~~


by 페라카스 [2008.05.13 14:53:17]
^^; 까묵으시면 어떻게해요..
3의 Record 0 라고 리턴하는건 안되요.. 어찌 방법이 없을까요? ㅠ.ㅠ

by 된장 [2008.05.13 14:57:09]
EXIT WHEN 커서명%NOTFOUND; <--요거는 없어두 되겠네요..
그렇다면 다 Exception으로 넘어갈 듯 한데...잘 모르겠음...
실행을 해봐야....어떤 에러가 나는지 알 수 있으니깐요..
o_cur:=0;이 리턴 시키는 것인뎅...
o_cur이 아웃 파라미터라서...거기에 값이 들어가면...나중에 배출됩니다..
통산 리턴되는 값이 하나라면...걍 Function으로 구현하지 않나요?....

by 페라카스 [2008.05.13 15:14:09]
리턴되는 Record는.. (Field가 아니라요..) 없을 수도.. 여러개일 수도.. 한개일 수도 있습니다. 그러니까.. Select 결과 그대로 넘겨야 하는데.. MSSQL에서는 그냥 자알 넘겨 주던데 Oracle은 에러를 발생 시켜 버리네요..ㅠ.ㅠ

o_cur := 0 을 하면 적용 자체가 안됩니다. (SQLGate씁니다)
PLS-00382: expression is of wrong type 이라고 에러를 리턴하네요..

by 된장 [2008.05.13 15:34:34]
CREATE OR REPLACE function SCOTT.TEST_P(p_a number) return number
is
cursor Cur_1 is
select ename,sal,hiredate
from emp
where empno in (7369,7499);
total_num number;
begin
total_num:=0;
for emp_rec in Cur_1 loop
total_num:=total_num+1;
end loop;
RETURN TOTAL_NUM;
Exception
when NO_DATA_FOUND THEN
RETURN 0; --데이터가 없음.
WHEN OTHERS THEN
RETURN 9999; --은하철도 999임의적 에러 넘버
end TEST_P;
/
헐....착각했네요...걍 FUNCTION으로 만들어봤는데..
참고가 될까요?...

by 페라카스 [2008.05.13 15:41:33]
PROCEDURE GET_DATA(
o_cur OUT t_cur
) IS

요런식으로 선언에 cursor로 반환하겠다. 해버려서 RETURN 0 가 안먹어요.. ㅠ.ㅠ
아.. 글구.. 이넘은.. 패키지입니다..

by 된장 [2008.05.13 16:01:17]
Return 0은 사용할 필요가 없을 듯 한데염...
프로시져니까 O_CUR에만 값을 집어넣어믄 뭔가가 알아서 사용할꺼구염...
T_Cur사용자 정의 type인가보네요...음냐....
근디 O_Cur에는 어떤 형식으로 들어가는지...기존에 대입하는 방식이 있다면
그거 참고해서 넣으면 될 듯 한뎅...Type이 뭔지 몰라서 ㅠㅠ..

by 페라카스 [2008.05.13 16:04:35]
t_cur은 사용자 정의 커서가 맞구요.
o_cur에 들어가는 형식은.. ;; 7가지 정도가 있습니다..
문서에 대한 처리인데 문서 타입이 크게 7가지거든요.
그래서 GOTO를 이용해서 각부분에서 처리한뒤 임시적으로 p_cur 라는데에 일단 넣었다가 마지막에 다시 o_cur에 넣도록 되어 있습니다.

by 된장 [2008.05.13 16:10:51]
그렇다면 문제 없을 것 같은데염..
이 프로시져를 수행하고 나서 값이 없다면
O_CUR도 값이 없이 나갈 것이고...
O_CUR.EMPNO을 비교해서 그 값이 NULL이라면 검색된 값이 없다고..
PACKAGE 내에서 사용하면 되지 않을까..생각을 해보는 데염..~~..
만일 이렇게 해도 안되면...
저도 사용해본적이 없어서..
이 이상은 현업에 있는 고수님들에게 물어보셔야 될 듯 합니다.

by finecomp [2008.05.13 16:34:27]
오라클은 mssql server와 달리 일반 커서의 결과를 반환하지 못합니다.

프로시져에서 커서의 결과집합을 통째로 반환하려 하시는 거라면 오라클버전에 따라 ref cursor나 SYS_REFCURSOR의 내용을 좌측의 강좌나 웹검색으로 찾아보신 후 적용하시면 될 겁니다.

버전이 낮아 SYS_REFCURSOR를 사용하지 못하고 ref cursor를 써야 한다면 패키지 spec에 ref cursor type을 선언하시고 body에서 그 커서를 open하고 프로시져를 끝내면 됩니다.

by 페라카스 [2008.05.13 16:42:35]
finecomp님.. SYS_REFCURSOR가 존재하는건 몰랐네요.. -0-
당연히 ref cursor를 패키지 spec에 선언하고 body에서 open 했습니다.
그런데 "ORA-01023: 커서 문맥이 없습니다(부적합한 커서번호)." 라는 에러가 발생합니다.. 분명히 전에는 이상 없이 사용했던 방법입니다.
지금 Oracle이 10g인데.. 10g에서는 지원안하는건 아니겠죠? ㅡㅡ;
계속 하다보니 제가 어디선가 실수 한듯도 싶은데.. 전체 문장을 올릴 수도 없고.. 미치긋습니다.
DECLARE BEGIN END 로 Cursor 반환하는것좀 가르쳐 주세요.. ㅠ.ㅠ 미리 테스트 해보고 적용했으면 하는데.. 미리 테스트 하는 방법도 모르겠고..ㅠ.ㅠ

by 페라카스 [2008.05.13 16:45:23]
강좌란과 문답게시판은 2주째 쳐다 보고 있답니다..ㅠ.ㅠ

by finecomp [2008.05.13 16:46:51]
화면 맨 윗부분 오라클클럽 검색 란에서 SYS_REFCURSOR로 검색하여 팁의 내용을 살펴보세요...^^;

by 페라카스 [2008.05.13 16:51:33]
함수의 생성이나 프로시져의 생성 없이 테스트를 해볼 수는 없는건가요??? (SQLGate 이용중입니다) (편집 귀찮아 테스트 할려고 한거 그냥 올려봅니다)


DECLARE
O_CUR SYS_REFCURSOR;

p_TKG_FIRST_TKTNO VARCHAR(20);
BEGIN
SELECT TKG_FIRST_TKTNO
INTO p_TKG_FIRST_TKTNO
FROM FEP_TKG_TBL
WHERE TKG_TKTNO = '988 5727979179'
AND ROWNUM < 2;

OPen O_CUR FOR
SELECT 0 IDX,
'' HEADER_REMARKS,
A.*,
SF_CUT_PRICE(A.TKG_FOP) TKG_FOP_CASE,
CASE WHEN TKG_PDTAX IS NULL OR TKG_PDTAX = '' THEN ''
ELSE 'PD' || REPLACE(SF_REPLACE(TKG_PDTAX, ' ', ' '), ' ', ' PD')
END TKG_PDTAX_CASE,
CASE WHEN A.TKG_CHILDFACT IS NULL AND A.TKG_FFPNO IS NULL THEN ''
WHEN A.TKG_CHILDFACT IS NULL THEN '(' || A.TKG_FFPNO || ')'
WHEN A.TKG_FFPNO IS NULL THEN '(' || A.TKG_CHILDFACT || ')'
ELSE '(' || A.TKG_CHILDFACT || ' / ' || A.TKG_FFPNO || ')'
END PASSENGER_NAME,
CASE WHEN A.TKG_EXG_TKTNO IS NULL OR A.TKG_EXG_TKTNO = '' THEN ''
ELSE '(EXCHANGED TKT: ' || TKG_EXG_TKTNO || ' ORIGINAL TKT: ' || TKT_ORIG_TKTNO || ')'
END TKT_CASE,
CASE WHEN A.TKG_AIRLINE_PNR IS NULL OR A.TKG_AIRLINE_PNR = '' THEN ''
ELSE '(' || A.TKG_AIRLINE_PNR || ')'
END TKG_AIRLINE_PNR_CASE
FROM FEP_TKG_TBL A
WHERE A.TKG_TKTNO = p_TKG_FIRST_TKTNO;

return O_CUR;
END;

by finecomp [2008.05.13 16:57:35]
SQL Gate가 일반 app tool들 처럼 반환된 커서집합을 전부 받아서 보여 줄 수 있는지는 의문입니다.(제가 안써봤습니다...ㅡ.ㅡ;)
단순히 테스트를 원하시는 거라면 커서의 내용을 DBMS_OUTPUT으로 찍어보는 것은 어떨가 합니다만...^^;

데이터의 정합성만이 아닌,
반드시 커서반환의 테스트까지 해야겠다면 vb등 일반 app tool로 그냥 간단히 만드세요...^^;

by 페라카스 [2008.05.13 17:00:30]
SQLGate야.. 그냥 Toad랑 비슷하다고 생각하시면 됩니다.
return 대신 DBMS_OUTPUT.PUT_LINE(O_CUR.TKG_PDTAX_CASE); 라고 했더만.. 에러 나네요..ㅠ.ㅠ

by 페라카스 [2008.05.13 17:02:36]
참...글구.. 그 VB로 테스트 하고 있었는데..
ORA-01023: 커서 문맥이 없습니다(부적합한 커서번호).
라고만 에러 나요.. ㅠ.ㅠ

by finecomp [2008.05.13 17:11:28]
1. 커서의 내용을 찍어보려면 일단 Loop로 돌려 fetch하면서 한줄씩 찍어봐야겠죠...;

2. vb에서 프로시져의 call 시 오류가 있다면 데브피아등을 참고하여 올바른 sys_refcursor 반환 프로시져 call 코딩방법을 확인 하셔야겠죠...;

여러가지 다양한 상황들을 혼자만 알고계시니 질문/답변만으론 한계가 있습니다.
올바른 방향이 정해지면 나머지 실제 구현에 관한부분은 본인이 하나하나 확인해가면서 만들 수 밖에 없을 겁니다...;

건승하시길...수고하세요...^^;

by 페라카스 [2008.05.13 17:11:46]
써어글.. 짜아증...
저번에 같은 에러가 나서 테스트로 GOTO PRC_END를 첫줄에 넣었는데..
그걸 빼는걸 까먹고 있었네요... 아놔.. 아놔.. 미쳐 부려...
근데..수정된게 거의 없는데 오늘은 왜 되는거지? ㅠ.ㅠ

by 된장 [2008.05.13 17:15:27]
ㅋㅋㅋㅋㅋ....되면 좋은 거죠....ㅋㅋ..추카추카..ㅋㅋ

by finecomp [2008.05.13 17:16:09]
아무튼 된다니 다행이군요...괜히 맘 고생 많으셨겠습니다...ㅎㅎ

by 페라카스 [2008.05.13 17:18:23]
되는건 간단한 로직 타는쪽이었고.. 또 그 메시지는 나오는데..
수동으로 SELECT 해보니 해당 Record가 없네요..
그냥.. 맘 편하게.. 없어서 그런가 보다 하고 넘길랍니다.. ㅠ.ㅠ
성원해 주셔서.. 감사합니다.. ^^
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입