8장 .예외처리 ORACLE /PL/SQL 2014. 2. 16. 21:41

8. 예외 처리

SQL> ALTER TABLE emp

ADD CONSTRAINT emp_ck CHECK ( sal > 0 ) ;  --제약조건 추가하고 실습시작.

 

SQL>

SELECT empno, ename, sal

FROM emp

WHERE deptno = 10 ;

 

EMPNO ENAME SAL

---------- ---------- ----------

7782 CLARK 2450

7839 KING 5000

7934 MILLER 1300

--------------------------------

 

BEGIN

             UPDATE emp

             SET sal = 3000

             WHERE empno = 7782 ;    --정상 수행 가능한 문장.

 

             UPDATE emp

             SET sal = 0

             WHERE empno = 7934 ;    --제약조건 위배, Error문장.

END ;

/

ERROR at line 1:

ORA-02290: check constraint (ORA1.EMP_CK) violated

ORA-06512: at line 6

 

→ PL/ SQL 블럭중에서 하나라도 실패하는게 있다면, 정상 수행되는 문장도 수행되지 않는다.

 

SQL> SELECT empno, ename, sal

FROM emp

WHERE deptno = 10 ;

EMPNO ENAME SAL

---------- ---------- ----------

7782 CLARK 2450

7839 KING 5000

7934 MILLER 1300

 

#TX-0 OPEN

             UPDATE emp

             SET sal = 9999

             WHERE empno = 7782 ;

BEGIN

             UPDATE emp

             SET sal = 3000

             WHERE empno = 7782 ;    --정상 수행 가능한 문장.

 

             UPDATE emp

             SET sal = 0

             WHERE empno = 7934 ;    --제약조건 위배, Error문장.

END ;

/

 

SQL> SELECT empno, ename, sal

FROM emp

WHERE deptno = 10 ;

EMPNO ENAME SAL

---------- ---------- ----------

7782 CLARK 9999

7839 KING 5000

7934 MILLER 1300

 

→ PL/SQL블럭이 성공이 되든 실패가 되든 사용자가 COMMIT/ ROLLBACK 하지 않으면

트랜잭션은 종료되어있지 않다. update문은 성공하고 PL/SQL블럭은 실패한 결과를 보여준다.

 

 

Ex1) 모든 ERROR상황은 OTHERS를 통해 잡을 수 있다.

SET SERVEROUTPUT ON

BEGIN

 UPDATE EMP

 SET SAL = 3000

 WHERE EMPNO = 7782;

 

 UPDATE EMP

 SET SAL = 0

 WHERE EMP = 7934 ;

 

EXCEPTION

 WHEN OTHERS THEN

   DBMS_OUTPUT.PUT_LINE('ERROR');

END;

/

 

EX2)

SET SERVEROUTPUT ON

BEGIN          --암시적으로 세이브 포인트가 생긴다.

 UPDATE EMP

 SET SAL = 3000

 WHERE EMPNO = 7782;       --실행됨.

 

 UPDATE EMP

 SET SAL = 0

 WHERE EMP = 7934 ;           --실행안됨 Exception 절로넘어가서 필요한 처리기로간다.

 

 UPDATE EMP

 SET SAL = 3000

 WHERE EMPNO = 7782;      --시도조차 하지 않는다.

 

 

EXCEPTION

 WHEN NO_DATA_FOUND THEN

  DMBS_OUTPUT.PUT_LINE('NO DATA');

 

 WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE('ERROR');   --에러처리를 한다.

END;

/

 

#에러를 핸들링 하지 못한다면 해당 PL/SQL블럭은 취소가 된다.

 

 

 

EX)오라클 서버로부터 만들어진 암시적 에러

SET SERVEROUTPUT ON

DECLARE

 V_SAL NUMBER ;

BEGIN

 SELECT SAL INTO V_SAL

 FROM EMP

 WHERE EMPNO= 1234 ;

END ;

/

 

ERROR at line 1:

ORA-01403: no data found

ORA-06512: at line 4

 

Ex) SQLERRMM 을 이용한 에러 확인.

 

SQL> SET SERVEROUTPUT ON

BEGIN

UPDATE emp

SET sal = 3000

WHERE empno = 7782 ;

UPDATE emp

SET sal = 0

WHERE empno = 7934 ;

EXCEPTION

WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE ( SQLERRM ) ;

END ;

/

ORA-02290: check constraint (ORA1.EMP_CK) violated

PL/SQL procedure successfully completed.

 

미리 정의된 예외 처리

ex)

SET SERVEROUTPUT ON

DECLARE

  emp_rec emp%ROWTYPE ;

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE ename = UPPER('&name') ;

  DBMS_OUTPUT.PUT_LINE ( emp_rec.sal ) ;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE ('NO_DATA_FOUND') ;

WHEN TOO_MANY_ROWS THEN

  DBMS_OUTPUT.PUT_LINE ('TOO_MANY_ROWS') ;

WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE ('OTHERS') ;

END ;

/

Enter value FOR name: RYU OLD 6: WHERE ename = UPPER('&name') ;

NEW 6: WHERE ename                           = UPPER('RYU') ;

NO_DATA_FOUND PL/SQL

PROCEDURE successfully completed.

 

 

 

 

 

 

미리 정의되지 않은 예외 처리

ex)

 

SET SERVEROUTPUT ON

DECLARE

  emp_rec emp%ROWTYPE ;

  e_ck EXCEPTION ;

  PRAGMA EXCEPTION_INIT (e_ck , -2290) ;  --예외생성.

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE ename = UPPER('&name') ;

  IF emp_rec.sal < 2000 THEN

    UPDATE emp SET sal = &salary WHERE empno = emp_rec.empno ;

  END IF ;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE ('NO DATA') ;

WHEN E_CK THEN

  DBMS_OUTPUT.PUT_LINE ('Invalid Salary') ;

WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE (SQLERRM) ;

END ;

/

 

사용자 정의 예외

 

SET SERVEROUTPUT ON

DECLARE

  v_deptno             NUMBER       := 50 ;

  v_name               VARCHAR2(20) := 'Testing' ;

  e_invalid_department EXCEPTION;

BEGIN

  UPDATE dept SET dname = v_name WHERE deptno = v_deptno ;

  IF SQL%NOTFOUND THEN

    RAISE e_invalid_department ;

  END IF;

  COMMIT;

EXCEPTION

WHEN e_invalid_department THEN

  DBMS_OUTPUT.PUT_LINE('No such department id.');

END;

/

No such department id. PL/SQL

PROCEDURE successfully completed.

 

※ RASE_APPLICATION_ERROR 사용

 

마치 오라클 서버에서 만들어진것 처럼 ERROR코드와 ERROR메세지가 나온다.

비정상종료를 강제로 유발시키고자할때 사용한다(암시적인 에러와 동일하다)

이전에 정상실행된 SQL문이 있더라도 ROLLBACK된다.

 

BEGIN

  UPDATE dept SET dname = 'Testing' WHERE deptno = 50 ;

  IF SQL%NOTFOUND THEN

    RAISE_APPLICATION_ERROR ( -20001, 'No such department id.' ) ;

  END IF;

END;

/

 

ERROR at line 1:

ORA-20001: No such department id.

ORA-06512: at line 7

 

ex2) 사용자 정의 에러문장은 보여주지만, 정상종료된다.

 

BEGIN

  UPDATE dept SET dname = 'Testing' WHERE deptno = 50 ;

  IF SQL%NOTFOUND THEN

    RAISE_APPLICATION_ERROR ( -20001, 'No such department id.' ) ;

  END IF;

EXCEPTION

WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE(SQLERRM) ;

END;

   /

ORA-20001: No such department id. PL/SQL

PROCEDURE successfully completed.

 

Ex3)

DECLARE

  emp_rec emp%ROWTYPE ;

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE deptno = 10 ;

EXCEPTION

WHEN TOO_MANY_ROWS THEN

  RAISE_APPLICATION_ERROR ( -20001, 'Too Many Rows', TRUE ) ;

                                                                                      --FALSE 로 변경하면, 원래에러메시지만 나온다.

END ;

                    /

ERROR at line 1: ORA-20001: Too Many Rows ORA-06512: at line 9 ORA-01422: exact

FETCH returns more than requested NUMBER OF rows

 

 

예외 전달

ex1)

BEGIN

  UPDATE emp SET sal = 7777 WHERE empno = 7788 ;

  BEGIN

    UPDATE emp SET sal = 9999 WHERE empno = 7566 ;

    UPDATE emp SET sal = 0 WHERE empno = 7839 ;

    UPDATE emp SET sal = 9999 WHERE empno = 7499 ;

  END ;        – ERROR1

  UPDATE emp SET sal = 7777 WHERE empno = 7369 ; 

END ;

/

ERROR1은 그 호출한 바깥으로 에러를 전달한다, 바깥쪽 블럭에도 EXCEPTION이 없기때문에 예외처리 되지 않으며, 어떠한 결과도 변경되지 않는다.

 

ERROR at line 1:

ORA-02290: check constraint (ORA1.EMP_CK) violated

ORA-06512: at line 11

SQL> SELECT empno, ename, sal

FROM emp

WHERE empno IN (7788, 7566, 7839, 7369, 7499) ;

 EMPNO ENAME SAL

---------- ---------- ----------

7369 SMITH 800

7499 ALLEN 1600

7566 JONES 2975

7788 SCOTT 3000

7839 KING 5000

EX2)

 

SQL> SET SERVEROUTPUT ON

BEGIN

  UPDATE emp SET sal = 7777 WHERE empno = 7788 ;

  BEGIN

    UPDATE emp SET sal = 9999 WHERE empno = 7566 ;

    UPDATE emp SET sal = 0 WHERE empno = 7839 ;        → Exception절로 이동한다.

    UPDATE emp SET sal = 9999 WHERE empno = 7499 ;  → 시도하지 않는다.

  EXCEPTION

  WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE (SQLERRM) ;

  END ;

  UPDATE emp SET sal = 7777 WHERE empno = 7369 ;  → 예외가 처리되었으므로 실행된다.

END ;

   /

ORA-02290: CHECK CONSTRAINT (ORA1.EMP_CK) violated PL/SQL

PROCEDURE successfully completed. SQL>

 

 

 

SELECT empno,

    ename,

    sal

FROM emp

WHERE empno IN (7788, 7566, 7839, 7369,7499) ;

 

  EMPNO ENAME SAL

  ---------- ---------- ----------

  7369 SMITH 7777 7499 ALLEN 1600 7566 JONES 9999 7788 SCOTT 7777 7839 KING 5000 SQL> ROLLBACK ;

 

 

EX3)

SQL>

SET SERVEROUTPUT ON

BEGIN

  UPDATE emp SET sal = 7777 WHERE empno = 7788 ;

  BEGIN

    UPDATE emp SET sal = 9999 WHERE empno = 7566 ;

    UPDATE emp SET sal = 0 WHERE empno = 7839 ;       → 에러 발생.

    UPDATE emp SET sal = 9999 WHERE empno = 7499 ;

  END ;

  UPDATE emp SET sal = 7777 WHERE empno = 7369 ;

EXCEPTION

WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE (SQLERRM) ;        → 에러처리.

END ;

/

 ORA-02290: check constraint (ORA1.EMP_CK) violated

PL/SQL procedure successfully completed.

SQL> SELECT empno, ename, sal

FROM emp

WHERE empno IN (7788, 7566, 7839, 7369,7499) ;

 EMPNO ENAME SAL

---------- ---------- ----------

7369 SMITH 800

7499 ALLEN 1600

7566 JONES 9999

7788 SCOTT 7777

7839 KING 5000

 

#정리다시해야함.

중첩된 데이터의 피엘에스큐엘을 사용하면 정상 적으로 되다가 서브블록이 호출되면

자기불럭의 익셉션 절을 찾고, 핸들링했다면 메인블럭으로 돌아와서 나머지명령을 실행한다.

서브블록에서 에러를 핸들링 하지못했다면(익셉션절이 없거나, 있지만 처리기가 제대로 되지않을경우)

메인절의 익셉션 절로 넘어가고 그 사이에있는 것은 실행조차 되지 않는다.

메인절에서 처리기를 정상 처리해줬다면 서브블럭은 정상처리된다.

 

BEGIN

 

   SQL 1

 

   SQL 2   - ERROR  EXCEPTION절로 넘어간다.

 

   SQL 3   -실행조차 하지않는다.

 

EXCEPTION

 

END ;

 

 

Q> 만약  SQL 3번을 꼭 사용해야한다면. 중첩된 블록을 이용한다.

BEGIN

 

   SQL 1

 

   BEGIN

            SQL 2 

   EXCEPTION

   END ;

            

   SQL 3                 

 

EXCEPTION

 

END ;

'ORACLE > PL/SQL' 카테고리의 다른 글

7장. 명시적 커서 사용  (0) 2014.02.16
6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16

7. 명시적 커서 사용


ex1)많은 행을 가져오므로 ERROR

SQL>

SET SERVEROUTPUT ON

DECLARE

  emp_rec emp%ROWTYPE ;

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE deptno = 10 ;

  DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

END ;

                    /

ERROR at line 1: ORA-01422: exact

FETCH returns more than requested NUMBER OF rows ORA-06512: at line 4

 


EX2) 커서 생성을 통한 여러 행 불러오기.

DECLARE

 CURSOR emp_cur   --Cursor 생성.

  IS

    SELECT * FROM emp WHERE deptno = 10 ;

  emp_rec emp%ROWTYPE ;

BEGIN

  OPEN emp_cur ;   --open이 되어야 문장이 실행된다.

  FETCH emp_cur INTO emp_rec ;  --첫번째 행만 FETCH.

  DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

  FETCH emp_cur INTO emp_rec ; --그 다음행 선별하여 꺼내온다.

  DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

  CLOSE emp_cur ;  --메모리 할당 해제.

END ;

                       /

7782 CLARK 7839 KING PL/SQL

PROCEDURE successfully completed.

 

Ex3) LOOP를 통한 반복.

DECLARE

  CURSOR emp_cur

  IS

    SELECT * FROM emp WHERE deptno = 10 ;

  emp_rec emp%ROWTYPE ;

BEGIN

  OPEN emp_cur ;

  LOOP

    FETCH emp_cur INTO emp_rec ;

    EXIT

  WHEN emp_cur%NOTFOUND ;

    DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

  END LOOP ;

  CLOSE emp_cur ;

END ;

                                   /

7782 CLARK 7839 KING 7934 MILLER PL/SQL

PROCEDURE successfully completed.

 

Ex3) For Loop문과 결합된 Cursor :  암시적으로 OPEN / FETCH / CLOSE가 수행된다.

DECLARE

  CURSOR emp_cur

  IS

    SELECT * FROM emp WHERE deptno = 10 ;

BEGIN

  FOR emp_rec IN emp_cur   --emp_rec선언 하지않아도 자동적으로 선언됨.

  LOOP

    DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

  END LOOP ;

END ;

                                   /

7782 CLARK 7839 KING 7934 MILLER PL/SQL

PROCEDURE successfully completed.

 

Ex4)

BEGIN

  FOR emp_rec IN

  ( SELECT * FROM emp WHERE deptno = 10

  )

  LOOP

    DBMS_OUTPUT.PUT_LINE ( emp_rec.empno || ' ' || emp_rec.ename ) ;

  END LOOP ;

END ;

/

7782 CLARK

7839 KING

7934 MILLER

PL/SQL procedure successfully completed.

 

 

 

Ex4) Parameter가 포함된 커서.

DECLARE

  CURSOR emp_cur ( p_deptno NUMBER )

  IS

    SELECT * FROM emp WHERE deptno = p_deptno ;

BEGIN

  FOR emp_rec IN emp_cur (10)

  LOOP

    DBMS_OUTPUT.PUT_LINE ( emp_rec.deptno || ' : ' || emp_rec.empno || ' ' || emp_rec.ename ) ;

  END LOOP ;

  FOR emp_rec IN emp_cur (20)

  LOOP

    DBMS_OUTPUT.PUT_LINE ( emp_rec.deptno || ' : ' || emp_rec.empno || ' ' || emp_rec.ename ) ;

  END LOOP ;

END ;

/

 

 

 

SELECT empno, ename, sal, deptno FROM emp

WHERE deptno = 10 FOR UPDATE ; --검색된 행에대해 LOCK이 걸린다.

 

※ WHERE CURRENT OF 절 사용

 

Ex1)현재 내가 FETCH 해온 그 행에대해 직접적인 UPDATE를 한다.

DECLARE

  CURSOR emp_cur

  IS

    SELECT * FROM emp WHERE deptno = 10 FOR UPDATE ;

BEGIN

  FOR emp_rec IN emp_cur

  LOOP

    IF emp_rec.sal < 2000 THEN

      UPDATE emp SET sal = sal * 1.1 WHERE CURRENT OF emp_cur ; 

                                                                  /* WHERE empno = emp_rec.empno */         --최선이아니다!.   

    END IF ;

  END LOOP ;

END ;

/

 

전재 조건으로 반드시 해당 커서는 선언될 때 FOR UPDATE 절이 있어야한다.

LOCK이 많이 발생해 자주 쓸 순 없다.

 

* 해결방안. #음성178 확인50분 부터

DECLARE

  CURSOR emp_cur

  IS

    SELECT a.*, rowid rid from a  FROM emp a WHERE deptno = 10 FOR UPDATE ;

BEGIN

  FOR emp_rec IN emp_cur

  LOOP

    IF emp_rec.sal < 2000 THEN

      UPDATE emp SET sal = sal * 1.1 WHERE emp_rec.rid;

    END IF ;

  END LOOP ;

END ;

/

'ORACLE > PL/SQL' 카테고리의 다른 글

8장 .예외처리  (0) 2014.02.16
6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16

6. 조합 데이터 유형

 

※ PL/SQL Record

DECLARE

 TYPE emp_rec_typ IS RECORD              --레코드 구조체. 필드는 둘 이상.

 ( ename VARCHAR2(10),

      sal emp.sal%TYPE,

      job emp.job%TYPE := 'NONE' ) ;

  emp_rec   EMP_REC_TYP ;

 

BEGIN

 SELECT ename, sal, job INTO emp_rec

 FROM emp

 WHERE empno = 7788 ;

 

END ;

/

PL/SQL procedure successfully completed.

 

※ %ROWTYPE 사용

 

DECLARE

  emp_rec emp%ROWTYPE ; --테이블 emp의 이름 및 유형을 가져온다.

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE empno = 7788 ;

END ;

/

PL/SQL procedure successfully completed.

 

 

DECLARE

  emp_rec emp%ROWTYPE ;  --테이블,뷰이름%ROWTYPE

BEGIN

  SELECT * INTO emp_rec FROM emp WHERE empno = 7788 ;

  INSERT INTO copy_emp VALUES emp_rec ;

  SELECT * INTO emp_rec FROM emp WHERE empno = 7782 ;

  emp_rec.sal      := emp_rec.sal * 1.2 ;

  emp_rec.hiredate := SYSDATE ;

  UPDATE copy_emp SET ROW = emp_rec WHERE empno = 7782 ;

END ;

  /

PL/SQL

PROCEDURE successfully completed.


#추가해야함.





'ORACLE > PL/SQL' 카테고리의 다른 글

8장 .예외처리  (0) 2014.02.16
7장. 명시적 커서 사용  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16

1.IF

ex1)

SET SERVEROUTPUT ON

DECLARE

             v_myage NUMBER := 10 ;

BEGIN

             IF v_myage < 11 THEN

              DBMS_OUTPUT.PUT_LINE(' I am a child ');

             END IF;

END;

/

 I am a child

PL/SQL procedure successfully completed.

 

ex2)

DECLARE

             v_myage NUMBER := 31 ;

BEGIN

             IF v_myage < 11 THEN

              DBMS_OUTPUT.PUT_LINE(' I am a child ');

             ELSE

              DBMS_OUTPUT.PUT_LINE(' I am not a child ');

             END IF;

END;

/

I am not a child

PL/SQL procedure successfully completed.

 

 

Ex3) 초기화가 되지 않은 변수에대한 IF

DECLARE

             v_myage NUMBER ;

BEGIN

             IF v_myage < 11 THEN

              DBMS_OUTPUT.PUT_LINE(' I am a child ');

             ELSE

              DBMS_OUTPUT.PUT_LINE(' I am not a child ');

             END IF;

END;

/

I am not a child

PL/SQL procedure successfully completed.

 

-> NULL은 비교가 불가 하므로 ELSE로 넘어가서 I am not a child 출력.

 

 

Ex4) ELSIF

 

DECLARE

             v_myage NUMBER := 31 ;

BEGIN

             IF v_myage < 11 THEN

              DBMS_OUTPUT.PUT_LINE(' I am a child ');

             ELSIF v_myage < 20 THEN

              DBMS_OUTPUT.PUT_LINE(' I am young ');

             ELSIF v_myage < 30 THEN

              DBMS_OUTPUT.PUT_LINE(' I am in my twenties');

             ELSIF v_myage < 40 THEN

               DBMS_OUTPUT.PUT_LINE(' I am in my thirties');

             ELSE

               DBMS_OUTPUT.PUT_LINE(' I am always young ');

END IF;

END;

/

I am in my thirties

PL/SQL procedure successfully completed.

 

2. CASE 표현식 값을 할당할때, 또 다른 명령을 실행시킬때 사용


ex1)값을 할당할 때 

DECLARE

             v_grade CHAR(1) := UPPER('&grade') ;

             v_appraisal VARCHAR2(20) ;

BEGIN

             v_appraisal := CASE v_grade WHEN 'A' THEN 'Excellent'

                                                                   WHEN 'B' THEN 'Very Good'

                                                                   WHEN 'C' THEN 'Good'

                                                                   ELSE 'No such grade'

                                                                   END;

             DBMS_OUTPUT.PUT_LINE ('Grade: '|| v_grade || ' Appraisal ' || v_appraisal);

END;

/

 Enter value for grade: B

old 2: v_grade CHAR(1) := UPPER('&grade') ;

new 2: v_grade CHAR(1) := UPPER('B') ;

 Grade: B Appraisal Very Good

PL/SQL procedure successfully completed.

  

 ex2)또 다른 명령어를 실행하기 위한 CASE문

DECLARE

             v_sum NUMBER ;

             v_deptno NUMBER := &deptid ;

BEGIN

             CASE v_deptno

             WHEN 10 THEN

                           SELECT SUM(sal) INTO v_sum

                           FROM emp

                           WHERE deptno = 10 ;

             WHEN 20 THEN

                           SELECT SUM(sal) INTO v_sum

                           FROM emp

                           WHERE deptno = 20 ;

             WHEN 30 THEN

                           SELECT SUM(sal) INTO v_sum

                           FROM emp

                           WHERE deptno = 30 ;

             ELSE

                           SELECT SUM(sal) INTO v_sum FROM emp ;

             END CASE ;

DBMS_OUTPUT.PUT_LINE ( v_sum ) ;

END ;

/

 Enter value for deptid: 30

old 3: v_deptno NUMBER := &deptid ;

new 3: v_deptno NUMBER := 30 ;

 9400

PL/SQL procedure successfully completed.

 

3. Loop : 반복수행


EX1) Basic Loop

SQL> SET SERVEROUTPUT ON

DECLARE

             v_count NUMBER(2) := 1 ;

BEGIN

             LOOP

                           DBMS_OUTPUT.PUT_LINE ('count: '||to_char(v_count)) ;

                           v_count := v_count + 1 ;

                           EXIT WHEN v_count = 4 ;

             END LOOP ;

END;

/

 

count: 1

count: 2

count: 3

PL/SQL procedure successfully completed.

 

Ex2) While Loop

BEGIN

 WHILE v_count <= 3 

 LOOP

  DBMS_OUTPUT.PUT_LINE ('count: '||to_char(v_count)) ;

  v_count := v_count + 1 ;

 END LOOP ;

END ;

/

count: 1

count: 2

count: 3

PL/SQL procedure successfully completed.

 

Ex3) For Loop, 반복 횟수를 알고있을 때 사용

BEGIN

 FOR i IN 1..3 

 LOOP  

  DBMS_OUTPUT.PUT_LINE ('count: '||to_char(i)) ;

 END LOOP ;

END ;

/

count: 1

count: 2

count: 3

PL/SQL procedure successfully completed

 

Ex4)For  Loop는 암시적으로 카운터가 생긴다.

BEGIN

 FOR i IN 1..3 LOOP

  DBMS_OUTPUT.PUT_LINE ('count: '||to_char(i)) ;

 END LOOP ;

END ;

/

count: 1

count: 2

count: 3

PL/SQL procedure successfully completed

 

Ex5)  Reverse For Loop 거꾸로연산.

BEGIN

 FOR i IN REVERSE 1..3 

  LOOP

   DBMS_OUTPUT.PUT_LINE ('count: '||to_char(i)) ;

  END LOOP ;

END ;

/

count: 3

count: 2

count: 1

PL/SQL procedure successfully completed.

 

※ Nested Loops  중첩된 Loop를 빠져나갈때 Exit

DECLARE

  x NUMBER := 3 ;

  y NUMBER ;

BEGIN

  <<OUTER_LOOP>>

  LOOP

    y := 1 ;

    EXIT WHEN x > 5 ;

       <<INNER_LOOP>>

             LOOP

                DBMS_OUTPUT.PUT_LINE ( x || ' * ' || y || ' = ' || x * y ) ;

                y := y + 1 ;

                EXIT WHEN y > 5 ;

             END LOOP INNER_LOOP ;

    x := x + 1 ;

 END LOOP OUTER_LOOP ;

END ;

/

 

 

3 * 1 = 3

3 * 2 = 6

3 * 3 = 9

3 * 4 = 12

3 * 5 = 15

4 * 1 = 4

4 * 2 = 8

4 * 3 = 12

4 * 4 = 16

4 * 5 = 20

5 * 1 = 5

5 * 2 = 10

5 * 3 = 15

5 * 4 = 20

5 * 5 = 25

PL/SQL procedure successfully completed.

 

 

 DECLARE

x NUMBER := 3 ;

y NUMBER ;

BEGIN

<<OUTER_LOOP>>

LOOP

y := 1 ;

EXIT WHEN x > 5 ;

<<INNER_LOOP>>

LOOP

DBMS_OUTPUT.PUT_LINE ( x || ' * ' || y || ' = ' || x * y ) ;

EXIT OUTER_LOOP WHEN x*y > 15 ;

y := y + 1 ;

EXIT WHEN y > 5 ;

END LOOP INNER_LOOP ;

x := x + 1 ;

END LOOP OUTER_LOOP ;

END ;

/

 

4. CONTINUE :

11g부터 생긴것. Continue에 만족하는 사항이 생기면, 밑에 있는 것은 싫행하지말고첫번째 시퀀스부터 다시 시작함.

ex1)

SQL> SET SERVEROUTPUT ON

DECLARE

             v_total SIMPLE_INTEGER := 0;

BEGIN

             FOR i IN 1..5 LOOP

              v_total := v_total + i;

              DBMS_OUTPUT.PUT_LINE ('Total is: '|| v_total) ;

              CONTINUE WHEN i > 3 ;

              v_total := v_total + i;

              DBMS_OUTPUT.PUT_LINE ('Out of Loop Total is: '|| v_total);

             END LOOP;

END;

/

 Total is: 1 <= 0 + 1 (i)

Out of Loop Total is: 2 <= 1 + 1 (i)

Total is: 4 <= 2 + 2 (i)

Out of Loop Total is: 6 <= 4 + 2 (i)

Total is: 9 <= 6 + 3 (i)

Out of Loop Total is: 12 <= 9 + 3 (i)

Total is: 16 <= 12 + 4 (i)

Total is: 21 <= 16 + 5 (i)

PL/SQL procedure successfully

 

ex2)

SQL> SET SERVEROUTPUT ON

DECLARE

  v_total NUMBER := 0;

BEGIN

  <<BeforeTopLoop>>

  FOR i IN 1..5

  LOOP

    v_total := v_total + 1;

    DBMS_OUTPUT.PUT_LINE ('Outer Total is: ' || v_total) ;

    FOR j IN 1..5

    LOOP

      CONTINUE BeforeTopLoop

    WHEN i               + j > 5 ;

      v_total := v_total + 1;

      DBMS_OUTPUT.PUT_LINE ('Inner Total is: ' || v_total) ;

    END LOOP;

  END LOOP;

END ;

/

Outer Total is: 1 <= 0 + 1 (i=1)

Inner Total is: 2 <= 1 + 1 (i=1 , j=1)

Inner Total is: 3 <= 2 + 1 (i=1 , j=2)

Inner Total is: 4 <= 3 + 1 (i=1 , j=3)

Inner Total is: 5 <= 4 + 1 (i=1 , j=4)

Outer Total is: 6 <= 5 + 1 (i=2)

Inner Total is: 7 <= 6 + 1 (i=2 , j=1)

Inner Total is: 8 <= 7 + 1 (i=2 , j=2)

Inner Total is: 9 <= 8 + 1 (i=2 , j=3)

Outer Total is: 10 <= 9 + 1 (i=3)

Inner Total is: 11 <= 10 + 1 (i=3 , j=1)

Inner Total is: 12 <= 11 + 1 (i=3 , j=2)

Outer Total is: 13 <= 12 + 1 (i=4)

Inner Total is: 14 <= 13 + 1 (i=4 , j=1)

Outer Total is: 15 <= 14 + 1 (i=5)

PL/SQL procedure successfully completed.

 

'ORACLE > PL/SQL' 카테고리의 다른 글

7장. 명시적 커서 사용  (0) 2014.02.16
6장 . 조합데이터 유형  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16
2장 PL/SQL 변수 선언  (0) 2014.02.16

4장. PL/SQL 프로그램에서 SQL 문과 상호 작용


# SQL/PLSQL 호출범위

SQL

-         QUERY  : SELECT

-         DML      : Insert / Update / Delete / Merge

-         TCL       : COMMIT / ROLLBACK / SAVEPOINT                          PL/SQL은 여기까지만 허용한다.

------------------------------------------------------------------------------------------------------------------------------------

-         DCL      : GRANT /  REVOKE / 

-         DDL      : CREATE / DROP / ALTER / TRUNBCATE / RENAME  PL/SQL에서 호출 불가능.

 

DML( INSERT, UPDATE, DELETE )

사용자가 명시적으로 COMMIT을 하지 않는다면 COMMIT되지 않는다.

실제 PL/SQL을 업무에서 사용한다면 PL/SQL 블럭 내에 COMMIT ; 을 넣어준다.


ex1) INSERT

BEGIN

             INSERT INTO emp(empno, ename, sal, deptno)

             VALUES (1234, 'RYU', 3000, 20) ;

END ;

/

PL/SQL procedure successfully completed.

 

BEGIN

             UPDATE emp

             SET sal = 4000

             WHERE empno = 1234 ;

END ;

/

PL/SQL procedure successfully completed.

 

Ex2) DELETE

BEGIN

             DELETE emp

             WHERE empno = 1234 ;

END ;

/

PL/SQL procedure successfully completed.

DELETE사용시 완료가 되었다는 결과 확인만으로  1234가 있어서 영향을 받았는지, 아니면 0행이 지워졌는지 애매하다.


BEGIN

             UPDATE emp

             SET sal = 4000

             WHERE empno = 7788 ;

     

             UPDATE emp

             SET sal = 3500

             WHERE empno = 7566 ;

END ;

/

PL/SQL procedure successfully completed.

 

SELECT empno, sal FROM emp

WHERE empno IN (7788, 7566) ;


EMPNO SAL

---------- ----------

7566 3500

7788 4000

 

SQL> ROLLBACK ;

 

SQL>

SELECT empno, sal FROM emp

WHERE empno IN (7788, 7566) ;

EMPNO SAL

---------- ----------

7566 2975

7788 3000


#영향받은 행이 있는지 확인하는 방법.


SQL> SET SERVEROUTPUT ON

BEGIN

             UPDATE emp

             SET sal = 4000

             WHERE empno = 7788 ;

             DBMS_OUTPUT.PUT_LINE ( SQL%ROWCOUNT || ' rows updated') ;

                                                                  --직전 명령 수행에 영향받은 행의 건수 count

             DELETE emp

             WHERE deptno = 10 ;

             DBMS_OUTPUT.PUT_LINE ( SQL%ROWCOUNT || ' rows deleted') ;

END ;

/

1 rows updated

3 rows deleted

 

PL/SQL procedure successfully completed.

 SQL> ROLLBACK ;

  

※ SELECT : - FETCH가 필요하므로 SELECTINTO절이 필요하다.

                    - INTO 절의 변수에 값을 넣는다.

Ex 1)

SQL> SET SERVEROUTPUT ON

DECLARE

             v_ename VARCHAR2(10) ;

             v_sal emp.sal%TYPE ; --참조속성 선언.

BEGIN

             SELECT ename, sal INTO v_ename, v_sal

             FROM emp

             WHERE empno = 7788 ;    --v_ename과 v_sal은 스칼라변수기 떄문에, where 절을 사용하여 하나의 행을 저장해야한다.

             DBMS_OUTPUT.PUT_LINE ( v_ename || ' : ' || v_sal ) ;

END ;

/

 SCOTT : 3000

PL/SQL procedure successfully completed

 

Ex 2) 여러개의 행을 저장해야하므로 Error

SET SERVEROUTPUT ON

DECLARE

             v_ename VARCHAR2(10) ;

             v_sal emp.sal%TYPE ;

BEGIN

             SELECT ename, sal INTO v_ename, v_sal

             FROM emp

             WHERE deptno = 10 ;

             DBMS_OUTPUT.PUT_LINE ( v_ename || ' : ' || v_sal ) ;

END ;

/

ERROR at line 1:

ORA-01422: exact fetch returns more than requested number of rows

ORA-06512: at line 5

 

Ex  3)검색된 행이 없는 Error

SQL> SET SERVEROUTPUT ON

DECLARE

             v_ename VARCHAR2(10) ;

             v_sal emp.sal%TYPE ;

BEGIN

             SELECT ename, sal INTO v_ename, v_sal

             FROM emp

             WHERE empno = 1111 ;

             DBMS_OUTPUT.PUT_LINE ( v_ename || ' : ' || v_sal ) ;

END ;

/

ERROR at line 1:

ORA-01403: no data found

ORA-06512: at line 5

 

※ DDL, DCL PL/SQL에서 호출 불가능.

BEGIN

             DROP TABLE emp ;

END ;

/

ERROR at line 2:

ORA-06550: line 2, column 3:

PLS-00103: Encountered the symbol "DROP" when expecting one of the following:

( begin case declare exit for goto if loop mod null pragma raise return select update while with <an

identifier> <a double-quoted delimited-identifier> <a bind variable> <<continue close current delete

fetch lock insert open rollback

savepoint set sql execute commit forall merge pipe purge

 

 

#참고

SYS@ORCL>show parameter cursor; 

NAME                                    TYPE        VALUE

------------------------------------ ----------- ------------------------------

cursor_sharing                       string        EXACT

cursor_space_for_time            boolean     FALSE

open_cursors                         integer         50

        --동시에 오픈 할 수 있는 커서 50. (명시적커서)

session_cached_cursors               integer     50

--50개저장.


 

내 세션에서 만약 SQL이 실행 되었다면 별도의 공간(Closed Cuosor)에 실행계획을 저장하여 Library Cache를 들어가지 않고 확인한다.

명시적 커서를 이용하면 PL/SQL에서 조건에 맞는게 둘 이상 나올 경우 중간에 하나씩 하나씩 끊어갈 수 있다.

'ORACLE > PL/SQL' 카테고리의 다른 글

6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16
2장 PL/SQL 변수 선언  (0) 2014.02.16
1장. PL/SQL 소개  (0) 2014.02.16

 1. PL/SQL 에서의 함수 사용

 

ex1)단일행 함수 사용.

SET SERVEROUTPUT ON

 DECLARE

                v_desc_size INTEGER(5);

                v_prod_description VARCHAR2(70) := 'You can use this product with your radios for higher frequency';

 BEGIN

                v_desc_size := LENGTH(v_prod_description) ;

                DBMS_OUTPUT.PUT_LINE (v_desc_size) ;

END ;

/

 62

PL/SQL procedure successfully completed.

 

ex2)그룹함수는 scalar type에 사용될 수 없다.

DECLARE

                v_desc_size INTEGER(5);

                v_prod_description VARCHAR2(70) := 'You can use this product with your radios for higher frequency';

BEGIN

                v_desc_size := MAX(v_prod_description) ;

                DBMS_OUTPUT.PUT_LINE (v_desc_size) ;

END ;

/

ERROR at line 5:

ORA-06550: line 5, column 18:

PLS-00204: function or pseudo-column 'MAX' may be used inside a SQL statement only

ORA-06550: line 5, column 3:

PL/SQL: Statement ignored

 

ex3)그룹함수가 SELECT 명령어와 함께 쓰이면 사용가능하다.

DECLARE

         v_sum NUMBER ;

BEGIN

         SELECT SUM(sal) INTO v_sum

FROM emp ;

                DBMS_OUTPUT.PUT_LINE (v_sum) ;

END ;

/

29025

PL/SQL procedure successfully completed.

 

2. PL/SQL 에서 SEQUENCE 사용

 

ex1) 11g부터 제공됨.

SQL> CREATE SEQUENCE empno_seq START WITH 1000 ;

SQL> SET SERVEROUTPUT ON

DECLARE

                v_num NUMBER := empno_seq.NEXTVAL ;

BEGIN

                DBMS_OUTPUT.PUT_LINE ( v_num ) ;

END ;

/

 1000

 

ex2)

DECLARE

                 v_num NUMBER ;

BEGIN

                SELECT empno_seq.NEXTVAL INTO v_num

                FROM dual ;

                DBMS_OUTPUT.PUT_LINE ( v_num ) ;

END ;

/

1001

PL/SQL procedure successfully completed.

 

중첩 블록에서 변수의 범위

 

ex1) 상위 블럭에서 선언된 변수는 하위변수에서 참조가 가능하다.

SET SERVEROUTPUT ON

DECLARE

                v_outer VARCHAR2(100) := 'Outer Variable' ;

BEGIN

                DBMS_OUTPUT.PUT_LINE ('Outer : ' || v_outer ) ;

                           DECLARE

                                       v_inner VARCHAR2(100) := 'Inner Variable' ;

                           BEGIN

                                        DBMS_OUTPUT.PUT_LINE ('Outer : ' || v_outer ) ;

                                        DBMS_OUTPUT.PUT_LINE ('Inner : ' || v_inner) ;

                        END ;

DBMS_OUTPUT.PUT_LINE ('Outer : ' || v_outer ) ;

END ;

/

 

Outer : Outer Variable

Outer : Outer Variable

Inner : Inner Variable

Outer : Outer Variable

 

ex2)하위 블록에 선언된 변수는 상위변수에서 출력 불가능하다.

SQL> SET SERVEROUTPUT ON

DECLARE

             v_outer VARCHAR2(100) := 'Outer Variable' ;

BEGIN

             DECLARE

                           v_inner VARCHAR2(100) := 'Inner Variable' ;

             BEGIN

                           DBMS_OUTPUT.PUT_LINE ('Outer : ' || v_outer ) ;

             DBMS_OUTPUT.PUT_LINE ('Inner : ' || v_inner) ;

END ;

             DBMS_OUTPUT.PUT_LINE ('Outer : ' || v_outer ) ;

             DBMS_OUTPUT.PUT_LINE ('Inner : ' || v_inner) ;

 END ;

/

ERROR at line 11:

ORA-06550: line 11, column 39:

PLS-00201: identifier 'V_INNER' must be declared

ORA-06550: line 11, column 3:

PL/SQL: Statement ignored

 

Ex3) 같은 변수이름으로 만들 경우, 레이블을 통한 구분.

BEGIN <<outer>> --테이블에 별칭을 붙이듯 레이블을지정.

             DECLARE

                           v_father_name VARCHAR2(20):='Patrick';

                           v_date_of_birth DATE := TO_DATE('20-APR-1972','DD-MON-YYYY') ;

             BEGIN

                           DECLARE           

                                        v_child_name VARCHAR2(20):='Mike';

                                        v_date_of_birth DATE := TO_DATE('12-DEC-2002','DD-MON-YYYY') ;

                           BEGIN

                                        DBMS_OUTPUT.PUT_LINE('Father''s Name: '||v_father_name);

                                        DBMS_OUTPUT.PUT_LINE('Date of Birth: '||outer.v_date_of_birth);

                                        DBMS_OUTPUT.PUT_LINE('Child''s Name: '||v_child_name);

                                        DBMS_OUTPUT.PUT_LINE('Date of Birth: '||v_date_of_birth);

                           END;

             END;

END outer;

/

Father's Name: Patrick

Date of Birth: 20-APR-72

Child's Name: Mike

Date of Birth: 12-DEC-02

PL/SQL procedure successfully completed.

'ORACLE > PL/SQL' 카테고리의 다른 글

6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
2장 PL/SQL 변수 선언  (0) 2014.02.16
1장. PL/SQL 소개  (0) 2014.02.16

변수

 1.스칼라 데이터 (단일값 변수)  :한번에 하나의 행이 하나의 컬럼의 값.( 보통 “V_컬럼의 이름이용.)


DECLARE  -- 선언부 

 V_EMPNO    NUMBER(4);

 V_ENAME    VARCHAR2(10);

 V_SAL         NUMBER(7,2) ;

 V_DEPTNO  NUMBER (2);

BEGIN

  SELECT EMPNO,ENAME,SAL,DEPTNO

       INTO V_EMPNO,V_ENAME,V_SAL,V_DEPTNO

  FROM EMP 

 -- WHERE EMPNO = 7788;

END ;

/

→  이 경우 ERROR 발생한다. 단일행 변수는 하나의 행만 저장 가능하다.

A. 적절한 where절을 통해 반드시 한개의 행만 검색되도록 해야한다

 

Q)

DECLARE  

 V_EMPNO    NUMBER(4);

 V_ENAME    VARCHAR2(10);

 V_SAL         NUMBER(7,2) ;

 V_DEPTNO  NUMBER (2);

BEGIN

  SELECT EMPNO,ENAME,SAL,DEPTNO

       INTO V_EMPNO,V_ENAME,V_SAL,V_DEPTNO

  FROM EMP

  WHERE EMPNO = 1234;

END ;

/

A..조건에 맞는 1234 행이 없으므로 ERROR발생한다.


DECLARE 

 V_EMPNO    NUMBER(4)  := 1234;                  -- 할당 연산자 :=  를 통한 변수에 값 할당.

 V_ENAME    VARCHAR2(10) DEAFULT 'ABCD'; -- DEFAULT 를 통한 할당.

 V_SAL         NUMBER(7,2) ;

 V_DEPTNO  NUMBER (2); 

BEGIN

  V_EMPNO :=1234  ;

  V_ENAME :='ABCD';

END ;

/ 


# 변수선언

SQL>

SET SERVEROUTPUT ON

DECLARE

 v_hiredate DATE ;  -- 초기값이 없다면 기본 NULL을 가지고 시작한다.

                              -- (초기값이 없는것에 NOT NULL제약조건 사용할 수 없다.)

 v_deptno NUMBER(2) NOT NULL := 10 ;  -- NOT NULL 제약조건

 v_location VARCHAR2(13) := 'Atlanta';  

c_comm CONSTANT NUMBER := 1400 ;   -- CONSTANT를 통해 상수선언실행부에서 값을 수정불가.

BEGIN

 DBMS_OUTPUT.PUT_LINE ( v_hiredate ) ; 

 DBMS_OUTPUT.PUT_LINE ( v_deptno ) ; 

 DBMS_OUTPUT.PUT_LINE ( v_location ) ;

 DBMS_OUTPUT.PUT_LINE ( c_comm ) ;

END ;

/


# PL/SQL 에서 Date type의 주의 사항

SQL> ALTER SESSION SET nls_date_format = 'DD-MON-RR' ;

SQL> SET SERVEROUTPUT ON

DECLARE

 v_hiredate DATE := '09-DEC-13' ;

BEGIN

 DBMS_OUTPUT.PUT_LINE ( v_hiredate ) ;

END ;

/

 09-DEC-13

PL/SQL procedure successfully completed.

 

SQL> ALTER SESSION SET nls_date_format = 'RR/MM/DD' ;

SQL> SET SERVEROUTPUT ON

DECLARE

 v_hiredate DATE := '09-DEC-13' ;

BEGIN

 DBMS_OUTPUT.PUT_LINE ( v_hiredate ) ;

END ;

/

 09/12/13 << 올바른 값인가?

13년 12월 9일인지, 09년 12월 13일인지 애매하다.

PL/SQL procedure successfully completed.

 

A.해결: TO_DATE를 통한 형변환

SQL> ALTER SESSION SET nls_date_format = 'RR/MM/DD' ;

SQL> SET SERVEROUTPUT ON

DECLARE

 v_hiredate DATE := TO_DATE('09-DEC-13','DD-MON-RR') ;

BEGIN

 DBMS_OUTPUT.PUT_LINE ( v_hiredate ) ;

END ;

/

13/12/09

PL/SQL procedure successfully completed.

 SQL> ALTER SESSION SET nls_date_format = 'DD-MON-RR' ;

 

날짜는 날짜의 포멧의 영향을 받는다. TO_DATE를 통해 형변환을 하여 엉뚱한 값이 나오지 않게 한다.


# BINARY_FLOAT, BINARY_DOUBLE type 확인

SQL> SET SERVEROUTPUT ON

DECLARE

 bf_var binary_float ;

 bd_var binary_double ;

BEGIN

 bf_var := 270/35 ;

 bd_var := 140/0.35 ;

DBMS_OUTPUT.PUT_LINE ('bf: ' || bf_var );

DBMS_OUTPUT.PUT_LINE ('bd: ' || bd_var );

END ;

/

 bf: 7.71428585E+000

 bd: 4.0E+002

PL/SQL procedure successfully completed.


SQL> SET SERVEROUTPUT ON

DECLARE

 bf_var NUMBER ;

 bd_var NUMBER ;

BEGIN

 bf_var := 270/35 ;

 bd_var := 140/0.35 ;


 DBMS_OUTPUT.PUT_LINE ('bf: ' || bf_var );

 DBMS_OUTPUT.PUT_LINE ('bd: ' || bd_var );

END ;

/


bf: 7.71428571428571428571428571428571428571

bd: 400

PL/SQL procedure successfully completed


# %TYPE 사용

 –이점: 참조하는 테이블/컬럼의 구조적인 변경이 있을경우 수정을 해야하는데, %TYPE을 사용하면 변경하지 않아도 된다.

 

SQL> SET SERVEROUTPUT ON

DECLARE

 v_sal emp.sal%TYPE ;

BEGIN

 SELECT sal INTO v_sal

 FROM emp

 WHERE empno = 7788 ;


 DBMS_OUTPUT.PUT_LINE ( v_sal ) ;

END ;

/

 3000

PL/SQL procedure successfully completed.


# Bind Variable 사용

--호출환경에서 선언된 변수Sqlplus, sqldeveloper 에서 선언.


SQL> VARIABLE b_sal NUMBER

SQL> PRINT b_sal

B_SAL

----------


BEGIN

 SELECT sal INTO :b_sal  -- 호출함수에서 선언된 변수를 출력할 때  :을 붙인다.

 FROM emp

 WHERE empno = 7788 ;

END ;

/

PL/SQL procedure successfully completed.

SQL> PRINT b_sal

B_SAL

----------

3000

'ORACLE > PL/SQL' 카테고리의 다른 글

6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16
1장. PL/SQL 소개  (0) 2014.02.16
1장. PL/SQL 소개 ORACLE /PL/SQL 2014. 2. 16. 16:33

1

1. SQL 과 PL/SQL 의 차이


SQL      : 조건 분기 불가능, 루핑 불가능, 변수처리 불가능, 단문 형(화면에 가져와야 그 다음명령실행)

PL/SQL : ORACLE DBMS에서 SQL문장과 제어문을 함게 사용할 수 있다. 코드 실행단위에 블록 구조를 제공한다

              변수, 상수, 데이터타입, 조건문,루프,DB의 객체로 저장가능.


PL/SQL Fundamentals  p1-6그림 중요

 

2. PL/SQL 블럭


SQL> SET SERVEROUTPUT ON            --DBMS_OUT_PUT을 통해 보여주기위함.

DECLARE                                              --선언부( 데이터 이름과 타입 정의)

 emp_rec emp%ROWTYPE ;                   --테이블 구조를 통채로 참조.

 sum_rec emp_sum%ROWTYPE ;

BEGIN

 SELECT * INTO emp_rec                      -- 검색결과를 emp_rec에 저장.

 FROM emp

 WHERE empno = 7788 ;


 DELETE emp

 WHERE empno = 7788 ;

 

 UPDATE emp_sum

 SET sum_sal = sum_sal - emp_rec.sal

 WHERE deptno = emp_rec.deptno ;


 SELECT * INTO sum_rec

 FROM emp_sum

 WHERE deptno = emp_rec.deptno ;


  DBMS_OUTPUT.PUT_LINE ( 'SUM Salary : ' || sum_rec.sum_sal ) ;

END ;

/

SUM Salary : 7875

PL/SQL procedure successfully completed.


SQL         

--PL/SQL에서 수행된 SQL결과는  PL/SQL 블럭으로 리턴된다(보통은 SQL명령을쓴 호출환경에 출력됨.)

 사용자에게 보여주는것은 전체 PL/SQL의 최종결과 즉, 수행 되었는지 안되었는지만 보여준다.

 

이와같은 행동을 반복할 때 귀찮으므로 PROCEDURE 라는 것이 있다.

 

3. Procedure 생성   마치 뷰,테이블 등을 만드는 것 처럼 DB의 객체를 생성하는것이다.

 

CREATE OR REPLACE PROCEDURE delete_emp

 ( p_empno NUMBER) AS

 emp_rec emp%ROWTYPE ;

 sum_rec emp_sum%ROWTYPE ;

BEGIN

 SELECT * INTO emp_rec

 FROM emp

 WHERE empno = p_empno ;


 DELETE emp

 WHERE empno = p_empno ;


 UPDATE emp_sum

 SET sum_sal = sum_sal - emp_rec.sal

 WHERE deptno = emp_rec.deptno ;


 SELECT * INTO sum_rec

 FROM emp_sum

 WHERE deptno = emp_rec.deptno ;


 DBMS_OUTPUT.PUT_LINE ( 'SUM Salary : ' || sum_rec.sum_sal ) ;

END ;

/

Procedure created.

 

SQL> SET SERVEROUTPUT ON   -- DBMS.OUTPUT은 기본값이 OFF이므로 켜야한다.

SQL> EXECUTE delete_emp (7788)

 SUM Salary : 7875

PL/SQL procedure successfully completed.

 

SQL> ROLLBACK ;

 

'ORACLE > PL/SQL' 카테고리의 다른 글

6장 . 조합데이터 유형  (0) 2014.02.16
5장. 제어 구조 작성  (0) 2014.02.16
4장 PL/SQL 프로그램에서 SQL 문과 상호 작용  (0) 2014.02.16
3장 실행문 작성  (0) 2014.02.16
2장 PL/SQL 변수 선언  (0) 2014.02.16