Web develop/SQL

[SQL/ORACLE] 커서 (CURSOR) 형식, FOR문에 사용하는 커서, ORA-01422 에러

ForA 2019. 6. 16. 15:15
728x90

CURSOR

  • SELECT의 결과가 2개행 이상일 때 명시적으로 사용
  • 2개 행 이상을 출력하는 SELECT문을 저장하는 변수
    declare 
        --변수선언, 커서정의
        CURSOR 커서명 IS SELECT문장;
    begin
        OPEN 커서명; -- 커서 사용선언
            FETCH 커서명 INTO 변수명 --커서 사용. 데이터 1행 인출
        CLOSE 커서명; -- 커서 사용중지
    end;
    /

    declare
            CURSOR cur IS SELECT deptno,dname,loc FROM dept;
            vdept dept%rowtype; -- 테이블을 구성하는 모든 컬럼 참조
        begin
            OPEN cur;
                dbms_output.put_line('부서번호/부서명/위치');
                LOOP 
                    FETCH cur INTO vdept; 
                    EXIT WHEN cur%notfound; --커서를 통해 인출된 행이 없다면
                    dbms_output.put_line(vdept.deptno || '/' || vdept.dname || '/' || vdept.loc);
                END LOOP;
                CLOSE cur;
        end;
    /
  • 변수명 테이블%rowtype; —> 특정테이블이 갖는 모든 컬럼에 정의된 자료형 참조
  • EXIT WHEN cur%notfound; —> 인출되는 행이 없을시 종료

커서사용 안할시 발생되는 에러

declare
    vdeptno dept.deptno%type;
    vdname dept.dname%type;
    vloc dept.loc%type;
    begin
        SELECT deptno,dname,loc INTO vdeptno,vdname,vloc FROM dept;

    end;
/
--에러발생
  • ORA-01422: exact fetch returns more than requested number of rows
  • -> 에러발생 (요구된 것(1행)보다 더 많은 수의 행(2행이상)을 추출했다는 에러)
  • 조회(SELECT)결과가 2개 이상일 때 해결 → CURSOR 또는 LOOP 사용

FOR문에서 커서 사용

CREATE OR REPLACE PROCEDURE dept_member(vdeptno emp.deptno%type)
  IS
      CURSOR cur IS SELECT empno, ename, sal, to_char(hiredate,'yyyy"년" mm"월" dd"일"' ) AS hiredate
      FROM emp WHERE deptno = vdeptno;
            cnt NUMBER := 0;
  begin
      DBMS_OUTPUT.PUT_LINE('사원번호/사원명/급여/입사일');
            /*
            OPEN cur; 
            FETCH cur; 
            CLOSE cur; --> FOR문으로 변환 
            */
      FOR vemp IN cur 
          LOOP
              dbms_output.put_line(vemp.empno || '/' || vemp.ename || '/' || 
                                          vemp.sal || '/' || vemp.hiredate );
                            cnt := cnt+1;
          END LOOP;
                    dbms_output.put_line('총 인원은 '||cnt||'명 입니다.');
end;
/

-- 호출
EXEC dept_member(30);