본문 바로가기

배운 책들 정리/오라클로 배우는 데이터베이스 입문

0209 오라클 DB 입문 - PL/SQL, 커서와 예외처리

1 PL/SQL (저장할 수 없음/ 한번 쓰고 사라지는 데이터)

1. PL/SQL 구조

0) 정의

- DECLARE / BEGIN  / EXCEPTION / END 를 주로 쓴다

- BEGIN, END를 꼭 써야 한다.

- 명령어와 END를 쓴 후 ;을 써야 한다.

- 주석처리 방법 : /*  ~~~ */

- EXCEPTION : 예외 처리 (해당 오류가 발생하면 패스해라라는 식)

 

* 표현 방법

DECLARE

[실행에 필요한 여러 요소 선언]

BEGIN

[작업을 위해 실제 실행하는 명령어]

EXCEPTION

[PL/SQL 수행 도중 발생하는 오류 처리]

 

 

1) Hello, PL/SQL! 출력

--토드에서 편집하고 SQLPLUS에서 실행
--실행 결과를 화면에 출력
SET SERVEROUTPUT ON;
--
--Hello, PL/SQL! 출력
BEGIN
   DBMS_OUTPUT.PUT_LINE('Hello, PL/SQL!');
END;
/

2) 주석 다는 방법

--
--주석
--한줄 주석: CTRL + B
--여러줄 주석: /* 내용 */ 로 앞 뒤로 묶어줌
--
/*
BEGIN
--   DBMS_OUTPUT.PUT_LINE('Hello, PL/SQL!');
END;
/
*/

 

2. 변수와 상수

0) 정의

- 기본 표현식

* 변수

변수이름 자료형 := 값 또는 값이 도출 되는 여러 표현식 ;

* 상수

변수 이름 CONSTANT 자료형 := 값 또는 값을 도출하는 여러 표현식;

* 변수의 기본 값 정의

변수 이름 자료형 DEFAULT 값 또는 값 도출 되는 여러 표현식;

* 변수에 NULL 값 저장 막기

변수 이름 자료형 NOT NULL := 또는 DEFAULT 값 또는 값이 도출 되는 여러 표현식;

* 참조형

변수 이름 테이블 이름.열이름%TYPE;

 

1) 변수 선언

--변수 선언, 변수 값 출력
DECLARE
   V_EMPNO NUMBER(4) := 7788;
   V_ENAME VARCHAR2(10);
BEGIN
   V_ENAME := 'SCOTT';
   DBMS_OUTPUT.PUT_LINE('V_EMPNO : ' || V_EMPNO);
   DBMS_OUTPUT.PUT_LINE('V_ENAME : ' || V_ENAME);
END;
/
--

 

7788과 SCOTT으로 나온 결과 값

* 모르는 것

-  ||  : 더해주는 기능과 같다. (CONCAT 도 같은 기능을 한다)

 

 

2) 상수 선언

--상수 선언, 상수 값 출력
DECLARE
   V_TAX CONSTANT NUMBER(1) := 3;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_TEX : ' || V_TAX);
END;
/
--

* 모르는 것

V_TAX CONSTANT NUMBER(1) := LENGTH(3);
-- 결과 : V_TAX : 1

- LENGTH : 33을 입력하면 2글자가 나옴 (자리수를 반환하기 때문에)

3) 변수의 기본값 지정하기

--변수 기본값 선언, 출력
DECLARE
   V_DEPTNO NUMBER(2) DEFAULT 10;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_DEPTNO : ' || V_DEPTNO);
END;
/
--

* 모르는거

V_DEPTNO NUMBER(4,2) DEFAULT 10.123;
결과 값 : V_DEPTNO : 10.12

4자리를 표현하고 소수점은 2자리만 반환하기 때문에 10.12로 나온다

 

 

4) 변수에 NULL값 저장 막기

--빈 값 불가 설정, 값 출력
DECLARE
   V_DEPTNO NUMBER(2) NOT NULL := 10;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_DEPTNO : ' || V_DEPTNO);
END;
/
----빈 값 불가, 기본값 설정, 기본값 출력

* 모르는거

- 제약조건과 변수는 다르기 때문에 변수 선언문을 응용해서 제약조건을 사용하는건 불가능하다.

따라서, 값을 지정해줘야 한다.

 

5) DEFAULT로 설정할 경우

----빈 값 불가, 기본값 설정, 기본값 출력
DECLARE
   V_DEPTNO NUMBER(2) NOT NULL DEFAULT 10;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_DEPTNO : ' || V_DEPTNO);
END;
/

똑같은 결과 값이 나온다. (NOT NULL 조건이 있기 때문에)

6) 변수 이름 규칙 (테이블 이름, 열의 이름의 규칙과 같음) 

1. 같은 블록 안에서 식별자는 고유하고 중복될 수 없음.
2. 대, 소문자 구별 안함.
3. 테이블 이름 규칙과 같음
- 문자로 시작해야 함 (한글도 가능하지만 숫자로 시작을 못함)
- 이름은 30byte (영어 30자, 한글 15자)
- 영문자(한글가능),숫자(0-9),특수문자($,#,_)를 사용할 수 있습니다.
- SQL 키워드는 테이블 이름으로 사용 못함 (SELECT, FROM과 같은 이름은 X)

7) 변수의 자료형 (스칼라와 참조형)

* 스칼라형

- TRUE or FALSE 형태를 가짐.

 

* 참조형

- 구체적인 열을 갖다 쓰는 것과 테이블이 가지고 있는 모든 열을 갖다 쓰는 것으로 나눠진다

 

* 구체적인 열을 지정할 경우

변수 이름 테이블이름.열이름%TYPE
--변수의 자료형
--참조형
--특정 열을 참고하여 사용
DECLARE
   V_DEPTNO DEPT.DEPTNO%TYPE := 50;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_DEPTNO : ' || V_DEPTNO);
END;
/

--NUMBER(2) 를 참조함
DESC DEPT;
--같은 의미로 작성
DECLARE
   V_DEPTNO NUMBER(2) := 50;
BEGIN
   DBMS_OUTPUT.PUT_LINE('V_DEPTNO : ' || V_DEPTNO);
END;
/

* 하나의 열이 아닌 행 구조를 참조할 경우

변수 이름 테이블 이름%ROWTYPE;
--행 구조 전체를 참조 = 전체 열 사용 가능
DECLARE
   V_DEPT_ROW DEPT%ROWTYPE;
BEGIN
   SELECT DEPTNO, DNAME, LOC INTO V_DEPT_ROW
     FROM DEPT
    WHERE DEPTNO = 40;
   DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO);
   DBMS_OUTPUT.PUT_LINE('DNAME : ' || V_DEPT_ROW.DNAME);
   DBMS_OUTPUT.PUT_LINE('LOC : ' || V_DEPT_ROW.LOC);
END;
/

* 복합형, LOB형

- 컬렉션 (TABLE) : 하나의 열에는 같은 타입의 데이터만 들어갈 수 있다.

- 레코드 (RECORD) : 하나의 행에는 다른 타입의 데이터를 저장할 수 있다.

- LOB : 대용량 데이터를 저장할 때는 LOB 타입을 쓰면 된다.

3. 조건 제어문

0) 정의

IF-THEN : 조건이 하나라면 THEN에 있는 내용을 실행해라 

IF-THEN-ELSE : 조건이 만족하면 THEN의 내용을 실행하고 아니라면 딴거 실행

IF-THEN-ELSEIF : 조건을 여러개 만들어서 수행

 

1) IF -THEN

* 홀수

--홀수
DECLARE
   V_NUMBER NUMBER := 13;
BEGIN
   IF MOD(V_NUMBER, 2) = 1 THEN
      DBMS_OUTPUT.PUT_LINE('V_NUMBER는 홀수입니다!');
   END IF;
END;
/

* 짝수

DECLARE
   V_NUMBER NUMBER := 14;
BEGIN
   IF MOD(V_NUMBER, 2) = 1 THEN
      DBMS_OUTPUT.PUT_LINE('V_NUMBER는 홀수입니다!');
   END IF;
END;
/

 

2) IF-THEN-ELSE 

--IF-THEN-ELSE: 한가지 조건 만족하면 IF 안의 명령어 실행, 만족하지 않으면 ELSE 안의 명령어 실행
DECLARE
   V_NUMBER NUMBER := 14;
BEGIN
   IF MOD(V_NUMBER, 2) = 1 THEN
      DBMS_OUTPUT.PUT_LINE('V_NUMBER는 홀수입니다!');
   ELSE
      DBMS_OUTPUT.PUT_LINE('V_NUMBER는 짝수입니다!');
   END IF;
END;
/

짝수 값 또는 홀수 값을 입력하면 해당 값을 출력

 

3) IF-THEN-ELSEIF

--IF-THEN-ELSIF: 여러조건으로 순서대로 확인하고 만족하면 해당 명령어 실행, 모두 만족하지 않으면 ELSE의 명령어 실행
DECLARE
   V_SCORE NUMBER := 87;
BEGIN
   IF V_SCORE >= 90 THEN
      DBMS_OUTPUT.PUT_LINE('A학점');
   ELSIF V_SCORE >= 80 THEN
      DBMS_OUTPUT.PUT_LINE('B학점');
   ELSIF V_SCORE >= 70 THEN
      DBMS_OUTPUT.PUT_LINE('C학점');
   ELSIF V_SCORE >= 60 THEN
      DBMS_OUTPUT.PUT_LINE('D학점');
   ELSE
      DBMS_OUTPUT.PUT_LINE('F학점');
   END IF;
END;
/

입력 값에 따라 학점을 매겨진 결과 값.

 

4) CASE 조건문

* 단순 CASE

--CASE 조건문
--단순 CASE: 같다는 조건의 값으로 수행
DECLARE
   V_SCORE NUMBER := 87;
BEGIN
   CASE TRUNC(V_SCORE/10)
      WHEN 10 THEN DBMS_OUTPUT.PUT_LINE('A학점');
      WHEN 9 THEN DBMS_OUTPUT.PUT_LINE('A학점');
      WHEN 8 THEN DBMS_OUTPUT.PUT_LINE('B학점');
      WHEN 7 THEN DBMS_OUTPUT.PUT_LINE('C학점');
      WHEN 6 THEN DBMS_OUTPUT.PUT_LINE('D학점');
      ELSE DBMS_OUTPUT.PUT_LINE('F학점');
   END CASE;
END;
/
--

- 모르는 것

TRUNC : 소수점 버리는 것.

 

* 검색 CASE

--검색 CASE: 여러 조건식으로 수행
DECLARE
   V_SCORE NUMBER := 87;
BEGIN
   CASE
      WHEN V_SCORE >= 90 THEN DBMS_OUTPUT.PUT_LINE('A학점');
      WHEN V_SCORE >= 80 THEN DBMS_OUTPUT.PUT_LINE('B학점');
      WHEN V_SCORE >= 70 THEN DBMS_OUTPUT.PUT_LINE('C학점');
      WHEN V_SCORE >= 60 THEN DBMS_OUTPUT.PUT_LINE('D학점');
      ELSE DBMS_OUTPUT.PUT_LINE('F학점');
   END CASE;
END;
/

같은 결과 값

4. 반복 제어문

0) 정의

- 특정 작업을 반복해서 수행하는 것.

- FOR LOOP는 반복 횟수를 설정함.

 

1) 기본 LOOP

--기본 LOOP
DECLARE
   V_NUM NUMBER := 0;
BEGIN
   LOOP
      DBMS_OUTPUT.PUT_LINE('현재 V_NUM : ' || V_NUM);
      V_NUM := V_NUM + 1;
      EXIT WHEN V_NUM > 4;
   END LOOP;
END;
/

- 해당 쿼리는 LOOP와 EXIT WHEN의 조합임.

- V_NUM가 4를 넘을 때까지 반복하고 넘는다면 루프를 나오고 끝내라.

 

2) WHILE LOOP

--WHILE LOOP
--조건식을 만족할 때는 반복, 만족하지 않을 때는 종료
DECLARE
   V_NUM NUMBER := 0;
BEGIN
   WHILE V_NUM < 4 LOOP
      DBMS_OUTPUT.PUT_LINE('현재 V_NUM : ' || V_NUM);
      V_NUM := V_NUM + 1;
   END LOOP;
END;
/

V_NUM < 4 이하의 조건만 출력하는 것이기 때문에 0,1,2,3이 출력 된다.

 

3) FOR LOOP

* FOR LOOP 정순

--FOR LOOP
BEGIN
   FOR i IN 0..4 LOOP
      DBMS_OUTPUT.PUT_LINE('현재 i의 값 : ' || i);
   END LOOP;
END;
/

 

* FOR LOOP 역순

--FOR LOOP & 역순
BEGIN
   FOR i IN REVERSE 0..4 LOOP
      DBMS_OUTPUT.PUT_LINE('현재 i의 값 : ' || i);
      END LOOP;
END;
/

 

- 소수점 단위로 출력하고 싶다면 DECLARE로 출력해야 함

 

4) CONTINUE

--FOR LOOP & CONTINUE
--CONTINUE: 조건을 만족하면 계속 반복하라는 의미 = 명령어 실행하지 말고 계속 LOOP를 돌아라는 뜻
BEGIN
   FOR i IN 0..4 LOOP
      CONTINUE WHEN MOD(i, 2) = 1;
      DBMS_OUTPUT.PUT_LINE('현재 i의 값 : ' || i);
   END LOOP;
END;
/
--

- CONTINUE의 조건식에 해당하는 결과값이 나왔다면 해당 값을 넘어가고 결과값을  출력하는 수식.

5. 자료형이 다른 여러 데이터를 저장하는 레코드

0) 정의

레코드 : 자료형이 각기 다른 데이터를 하나의 변수에 저장하는데 사용

 

1) 레코드를 이용한 데이터 추가

--레코드 = 행과 유사 = 다른 타입의 데이터를 하나의 변수로 저장 가능
--레코드 정의
DECLARE
   TYPE REC_DEPT IS RECORD(
      deptno NUMBER(2) NOT NULL := 99,
      dname DEPT.DNAME%TYPE,
      loc DEPT.LOC%TYPE
   );
   dept_rec REC_DEPT;
BEGIN
   dept_rec.deptno := 99;
   dept_rec.dname := 'DATABASE';
   dept_rec.loc := 'SEOUL';
   DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || dept_rec.deptno);
   DBMS_OUTPUT.PUT_LINE('DNAME : ' || dept_rec.dname);
   DBMS_OUTPUT.PUT_LINE('LOC : ' || dept_rec.loc);
END;
/
--

2) 레코드를 이용한 데이터 추가 (INSERT INTO)

--레코드를 이용한 데이터 추가
--부서 테이블 복사
CREATE TABLE DEPT_RECORD AS SELECT * FROM DEPT;
SELECT * FROM DEPT_RECORD;
--데이터 추가
DECLARE
   TYPE REC_DEPT IS RECORD(
      deptno NUMBER(2) NOT NULL := 99,
      dname DEPT.DNAME%TYPE,
      loc DEPT.LOC%TYPE
   );
   dept_rec REC_DEPT;
BEGIN
   dept_rec.deptno := 99;
   dept_rec.dname := 'DATABASE';
   dept_rec.loc := 'SEOUL';
   
   INSERT INTO DEPT_RECORD
   VALUES dept_rec;
END;
/

값을&nbsp; 출력하는 것이 없기 때문에 입력만 되었다는 표시가 뜸.

- Values dept_rec는 데이터 타입이 보관되어 있는거랑 다름이 없다.

- 레코드는 행이기 때문에 다른 데이터 타입을 가져올 수 있다.

 

3) 업데이트

--테이블 조회
SELECT * FROM DEPT_RECORD;
--레코드를 이용한 데이터 변경
SET SERVEROUTPUT ON;
DECLARE
   TYPE REC_DEPT IS RECORD(
      deptno NUMBER(2) NOT NULL := 99,
      dname DEPT.DNAME%TYPE,
      loc DEPT.LOC%TYPE
   );
   dept_rec REC_DEPT;
BEGIN
   dept_rec.deptno := 50;
   dept_rec.dname := 'DB';
   dept_rec.loc := 'SEOUL';

   UPDATE DEPT_RECORD
      SET ROW = dept_rec
    WHERE DEPTNO = 99;
END;
/

여전히 출력해서 보여주지는 않음
50번 부서와 DB가 변경된 모습 (원래는 99 / DATABASE)

- SET ROW를 쓰면 한줄 전체를 바꿈

 

4) 레코드 안에 레코드 만들기

--레코드 안에 레코드 만들기 = 중첩 레코드
DECLARE
   TYPE REC_DEPT IS RECORD(
      deptno DEPT.DEPTNO%TYPE,
      dname DEPT.DNAME%TYPE,
      loc DEPT.LOC%TYPE
   );
   TYPE REC_EMP IS RECORD(
      empno EMP.EMPNO%TYPE,
      ename EMP.ENAME%TYPE,
      dinfo REC_DEPT
   );
   emp_rec REC_EMP;
BEGIN
   SELECT E.EMPNO, E.ENAME, D.DEPTNO, D.DNAME, D.LOC
     INTO emp_rec.empno, emp_rec.ename,
          emp_rec.dinfo.deptno,
          emp_rec.dinfo.dname,
          emp_rec.dinfo.loc
     FROM EMP E, DEPT D
    WHERE E.DEPTNO = D.DEPTNO
      AND E.EMPNO = 7788;

   DBMS_OUTPUT.PUT_LINE('EMPNO : ' || emp_rec.empno);
   DBMS_OUTPUT.PUT_LINE('ENAME : ' || emp_rec.ename);
   DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || emp_rec.dinfo.deptno);
   DBMS_OUTPUT.PUT_LINE('DNAME : ' || emp_rec.dinfo.dname);
   DBMS_OUTPUT.PUT_LINE('LOC : ' || emp_rec.dinfo.loc);
END;
/
--

출력이 된 모습

- dinfo REC_DEPT : 레코드를 변수로 dinfo라는 값으로 저장

5. 자료형이 같은 여러 데이터를 저장하는 컬렉션 (열)

1) 연관 배열

--컬렉션
DECLARE
   TYPE ITAB_EX IS TABLE OF VARCHAR2(20)
      INDEX BY PLS_INTEGER;

   text_arr ITAB_EX;

BEGIN
   text_arr(1) := '1st data';
   text_arr(2) := '2nd data';
   text_arr(3) := '3rd data';
   text_arr(4) := '4th data';

   DBMS_OUTPUT.PUT_LINE('text_arr(1) : ' || text_arr(1));
   DBMS_OUTPUT.PUT_LINE('text_arr(2) : ' || text_arr(2));
   DBMS_OUTPUT.PUT_LINE('text_arr(3) : ' || text_arr(3));
   DBMS_OUTPUT.PUT_LINE('text_arr(4) : ' || text_arr(4));
END;
/
--

- INTEGER : 정수

 

2) 연관 배열에서 레코드 사용 ( 연관 배열 + 자료형)

DECLARE
   TYPE REC_DEPT IS RECORD(
      deptno DEPT.DEPTNO%TYPE,
      dname DEPT.DNAME%TYPE
   );

   TYPE ITAB_DEPT IS TABLE OF REC_DEPT
      INDEX BY PLS_INTEGER;

   dept_arr ITAB_DEPT;
   idx PLS_INTEGER := 0;

BEGIN
   FOR i IN (SELECT DEPTNO, DNAME FROM DEPT) LOOP
      idx := idx + 1;
      dept_arr(idx).deptno := i.DEPTNO;
      dept_arr(idx).dname := i.DNAME;

      DBMS_OUTPUT.PUT_LINE(
         dept_arr(idx).deptno || ' : ' || dept_arr(idx).dname);
   END LOOP;
END;
/

전부 출력

3) ROWTYPE으로 연관 배열 자료형 지정

--연관 배열에서 참조형 %ROWTYPE 사용
DECLARE
   TYPE ITAB_DEPT IS TABLE OF DEPT%ROWTYPE
      INDEX BY PLS_INTEGER;

   dept_arr ITAB_DEPT;
   idx PLS_INTEGER := 0;

BEGIN
   FOR i IN(SELECT * FROM DEPT) LOOP
      idx := idx + 1;
      dept_arr(idx).deptno := i.DEPTNO;
      dept_arr(idx).dname := i.DNAME;
      dept_arr(idx).loc := i.LOC;

      DBMS_OUTPUT.PUT_LINE(
      dept_arr(idx).deptno || ' : ' ||
      dept_arr(idx).dname || ' : ' ||
      dept_arr(idx).loc);
   END LOOP;
END;
/
--

4) 컬렉션 메서드

--컬렉션 메서드 = 함수처럼 사용 가능
DECLARE
   TYPE ITAB_EX IS TABLE OF VARCHAR2(20)
      INDEX BY PLS_INTEGER;

   text_arr ITAB_EX;

BEGIN
   text_arr(1) := '1st data';
   text_arr(2) := '2nd data';
   text_arr(3) := '3rd data';
   text_arr(50) := '50th data';

   DBMS_OUTPUT.PUT_LINE('text_arr.COUNT : ' || text_arr.COUNT);
   DBMS_OUTPUT.PUT_LINE('text_arr.FIRST : ' || text_arr.FIRST);
   DBMS_OUTPUT.PUT_LINE('text_arr.LAST : ' || text_arr.LAST);
   DBMS_OUTPUT.PUT_LINE('text_arr.PRIOR(50) : ' || text_arr.PRIOR(50));
   DBMS_OUTPUT.PUT_LINE('text_arr.NEXT(50) : ' || text_arr.NEXT(50));

END;
/

- TYPE IS TABLE이라는 컬렉션과 INDEX가 있으면 연관 배열이다

- PRIOR() : () 전에 있는 숫자

- NEXT() : () 앞에 있는 숫자

2 커서와 예외 처리

0) 커서의 정의

- 명시적 커서 : 사용자가 직접 커서를 선언하고 사용하는 커서

(DEC : CURSOR IS // BEGIN : OPEN, FETCH, CLOSE // END) 

- 묵시적 커서가 존재함.

- 범용성 있게 사용 가능함

 

 

1) SELECT INTO 방식

--커서 = SELECT 나 DML과 같은 SQL문을 실행한 결과를 저장해놓고 값을 꺼내서 쓸 수 있음
--SELECT INTO = 하나의 행의 결과만 사용 가능 
DECLARE
   V_DEPT_ROW DEPT%ROWTYPE;
BEGIN
   SELECT DEPTNO, DNAME, LOC INTO V_DEPT_ROW
     FROM DEPT
    WHERE DEPTNO = 40;
   DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO);
   DBMS_OUTPUT.PUT_LINE('DNAME : ' || V_DEPT_ROW.DNAME);
   DBMS_OUTPUT.PUT_LINE('LOC : ' || V_DEPT_ROW.LOC);
END;
/
--

결과값

--커서 = 행의 결과의 개수 상관없이 사용 가능
--명시적 커서
--하나의 행의 결과를 저장하는 커서 = SELECT INTO
DECLARE
   -- 커서 데이터를 입력할 변수 선언
   V_DEPT_ROW DEPT%ROWTYPE;
   -- 명시적 커서 선언(Declaration)
   CURSOR c1 IS
      SELECT DEPTNO, DNAME, LOC
        FROM DEPT
       WHERE DEPTNO = 40;
BEGIN
   -- 커서 열기(Open)
   OPEN c1;
   -- 커서로부터 읽어온 데이터 사용(Fetch)
   FETCH c1 INTO V_DEPT_ROW;

   DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO);
   DBMS_OUTPUT.PUT_LINE('DNAME : ' || V_DEPT_ROW.DNAME);
   DBMS_OUTPUT.PUT_LINE('LOC : ' || V_DEPT_ROW.LOC);
   -- 커서 닫기(Close)
   CLOSE c1;
END;
/

- 결과값은 똑같으나 명시적 커서 선언으로 C1을 만들어 사용하는 모습을 볼 수 있다.

 

2) 여러행 지정

--여러 개의 행의 결과를 저장하는 커서
DECLARE
   -- 커서 데이터를 입력할 변수 선언
   V_DEPT_ROW DEPT%ROWTYPE;
   -- 명시적 커서 선언(Declaration)
   CURSOR c1 IS
      SELECT DEPTNO, DNAME, LOC
        FROM DEPT;
BEGIN
   -- 커서 열기(Open)
   OPEN c1;
   LOOP
      -- 커서로부터 읽어온 데이터 사용(Fetch)
      FETCH c1 INTO V_DEPT_ROW;
      -- 커서의 모든 행을 읽어오기 위해 %NOTFOUND 속성 지정 // 무한루프 방지 (BREAK랑 같음)
      EXIT WHEN c1%NOTFOUND; 
      
      -- 조건식을 부여하려면 무한루프방지문을 쓴 후에 조건식을 걸어야 한다 .
      
      
      DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || V_DEPT_ROW.DEPTNO
                        || ', DNAME : ' || V_DEPT_ROW.DNAME
                        || ', LOC : ' || V_DEPT_ROW.LOC);
   END LOOP;
   -- 커서 닫기(Close)
   CLOSE c1;
END;
/

여러개 행을 출력한 결과

3) FOR LOOP를 쓰는 커서문

--FOR LOOP를 사용하면 OPEN, FETCH, CLOSE 생략 가능하여 사용 방법이 간단함
DECLARE
   -- 명시적 커서 선언(Declaration)
   CURSOR c1 IS
   SELECT DEPTNO, DNAME, LOC
     FROM DEPT;
BEGIN
   -- 커서 FOR LOOP 시작 (자동 Open, Fetch, Close)
   FOR c1_rec IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE('DEPTNO : ' || c1_rec.DEPTNO || 
                         ', DNAME : ' || c1_rec.DNAME || 
                         ', LOC : ' || c1_rec.LOC
                          );
   END LOOP;
END;
/
--

- FOR LOOP를 쓰면 간단하게 확인할 수 있다.

 

* 핵심

- 실무에서는 FOR LOOP를 많이 쓴다.

- PL/SQL : 일회성으로 쓰고 사라진다.

- DECLARE // BEGIN // END

- WHEN-THEN // IF-THEN-ELSEIF

- CASE 등등..

- MOD : 나누기

- 복합형에는 레코드와 컬렉션이 있다.

 

 

728x90
반응형
LIST