[ Oracle - Procedure 함수_NULLIF.COALESCE ]

 

NULLIF와 COALESCE는 CASE 수식의 축약된 형태입니다.

NULLIF는 NVL 함수의 역입니다.

COALESECE는 DECODE 함수와 유사합니다.

 

예: NULLIF)

CREATE OR REPLACE PROCEDURE get_comm_pct (p_comm NUMBER) is

        v_result VARCHAR2(10);  

BEGIN

        v_result := NULLIF(p_comm, 0);

        DBMS_OUTPUT.PUT_LINE ('The commission percent is '|| v_result*100||'%');

END;

 

SQL> Exec get_comm_pct;

 

The commission percent is 20%

PL/SQL procedure successfully completed.

 

예: COALESCE)

CREATE OR REPLACE PROCEDURE get_comm_pct (p_comm NUMBER) is

            v_result number;

BEGIN

    v_result := COALESCE(p_comm, 0);    

    DBMS_OUTPUT.PUT_LINE ('The commission percent is '||v_result*100||'%');

END;

 

SQL> Exec get_comm_pct;

 

The commission percent is 20%

PL/SQL procedure successfully completed.

 

 

Posted by 농부지기
,

[ Oracle - Procedure 함수_NULL ]

 

1. IF 문에서 NULL 비교 방법

   * Oracle 에서는 '' 도 null 이고,    null 도 null 이다.

 

 정상 :

    1.   if :n.deptno is not null then

    2.   if  nvl(:new.qty_do,0) != 0  then

    3.   if  nvl(:new.qty_do,0) != 0  then

 

오류 :

     1.  if :n.deptno   =   null   then    ..

         pl-sql에서는 위와 같이 하면  null 이라고 비교가 되지 않는다.(즉, null 이여도 null 로 인식 하지 않는다).  물론 Error 도 없고. )

 

    2.   DECLARE    sYYMM   char(5);    -- 라고 정의 를 하면

         ..

          Script에서는    sYYMM = '' 이것도 아니고,       sYYMM  is Null    도 아니고

                                 sYYMM = ' '  이다. (즉, space  한 칸으로 들어간다.)

     

 

Posted by 농부지기
,

[ Oracle - Procedure BULK BIND(BULK COLLECT INTO문) ]

 

소스가 간단해지고, 처리속도가 빨라짐

 

커서를 사용한 예)

DECLARE

    // 변수선언

    TYPE RECTYPE IS RECORD (

        CODE TAB1.CODE%TYPE,

        NAME TAB1.NAME %TYPE);

    TYPE DATATYPE IS TABLE OF RECTYPE;

    DATA DATATYPE := DATATYPE(NULL);

    I PLS_INTEGER := 1;

    // 커서선언

    CURSOR C1 IS SELECT CODE, NAME FROM TAB1;

BEGIN

    FOR REC IN C1 LOOP 

        DATA.EXTEND;

        DATA(I).CODE := REC.CODE;

        DATA(I).NAME := REC.NAME;

        I := I + 1;

    END LOOP;

END;

/

경과시간 : 00:00:13.37

 

BULK COLLECT INTO문을 사용한 예)

DECLARE

    // 변수선언

    TYPE RECTYPE IS RECORD (

        CODE TAB1.CODE%TYPE,

        NAME TAB1.NAME %TYPE(;

    TYPE DATATYPE IS TABLE OF RECTYPE;

    DATA DATATYPE := DATATYPE(NULL);

BEGIN

    SELECT CODE, NAME

    BULK COLLECT INTO DATA

    FROM TAB1;

END;

/

경과시간 : 00:00:01.54

 

 

PL/SQL에서 쿼리시 Array Processing 처리방법  

----------------------------------------------
임시 테이블 생성
----------------------------------------------

connect scott/tiger;

DROP TABLE bb;

CREATE TABLE bb
(
  empno NUMBER,
  empname VARCHAR2(10)
);

----------------------------------------------
풀이
----------------------------------------------

DECLARE
v_array_size CONSTANT INTEGER := 100;
v_empno DBMS_SQL.NUMBER_TABLE;
v_empname DBMS_SQL.VARCHAR2_TABLE;

v_cur_qry INTEGER;
v_rtn_qry INTEGER;
v_fetch_cnt INTEGER;
v_SelectStmt VARCHAR2(2000);
v_InsertStmt VARCHAR2(2000);

c NUMBER;
dummy NUMBER;


begin
v_cur_qry := DBMS_SQL.OPEN_CURSOR;

v_SelectStmt := 'select empno, ename from emp';

DBMS_SQL.PARSE(v_cur_qry, v_SelectStmt, DBMS_SQL.V7);

DBMS_SQL.DEFINE_ARRAY(v_cur_qry, 1, v_empno, v_array_size, 1);
DBMS_SQL.DEFINE_ARRAY(v_cur_qry, 2, v_empname, v_array_size, 1);

v_rtn_qry := DBMS_SQL.EXECUTE(v_cur_qry);

loop
v_fetch_cnt := DBMS_SQL.FETCH_ROWS(v_cur_qry);

DBMS_SQL.COLUMN_VALUE(v_cur_qry, 1, v_empno);
DBMS_SQL.COLUMN_VALUE(v_cur_qry, 2, v_empname);
if v_fetch_cnt = 0 or v_fetch_cnt < v_array_size then
exit;
end if;
end loop;


/********************INSERT 처리부분*************************************/

-- Bulk Insert 이용 !

v_InsertStmt := 'insert into bb values (:num_array, :name_array)';

c:= DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c, v_InsertStmt, DBMS_SQL.native);

DBMS_SQL.BIND_ARRAY(c, ':num_array', v_empno);
DBMS_SQL.BIND_ARRAY(c, ':name_array', v_empname);

dummy := DBMS_SQL.EXECUTE(c);
DBMS_SQL.CLOSE_CURSOR(c);

/************************************************************************/

DBMS_SQL.CLOSE_CURSOR(v_cur_qry);
end sp_array;
/



----------------------------------------------
참고자료
----------------------------------------------

/* ------------------------------
벌크 바인딩 이용하기
------------------------------ */

1) Bulk Binding 이란?
PL/SQL의 벌크바인딩은 오라클8i의 새로운 기능이다.
벌크바인딩을 사용하면 모음의 항목에 따라 루프를 도는 PL/SQL 코드를 사용하지 않고도
모음에 있는 모든 항목에 작동하는 SQL 문을 작성할 수 있다.
SQL에서 PL/SQL로 전환하는 것(데이터를 페치해서 배열에 추가하는 것)을 "문맥전환
(context switch)"이라고 하며 이 과정에서 상당한 오버헤드가 소모된다.
하지만 벌크바인딩 기능을 사용하면 이런 오버헤드를 상당히 줄일수있다.

2) BULK COLLECT 사용하기 : select 문과 함께 사용

==> FETCH 문에 BULK COLLECT 예약어를 사용하여 커서에 의해 선택된 모든 데이터를 배열로
읽어들인다.
이 방법이 PL/SQL 루프를 사용해서 한번에 한행씩 페치하는 것보다 훨씬 빠르다.

DECLARE
CURSOR all_depts IS
SELECT deptno, dname
FROM dept
ORDER BY dname;

TYPE dept_id IS TABLE OF dept.deptno%TYPE;
TYPE dept_name IS TABLE OF dept.dname%TYPE;

dept_ids dept_id;
dept_names dept_name;
inx1 PLS_INTEGER;

v_InsertStmt VARCHAR2(2000);

BEGIN
OPEN all_depts;
FETCH all_depts BULK COLLECT INTO dept_ids, dept_names;
CLOSE all_depts;

/** Load한 데이터의 변형 **/

FOR inx1 IN 1..dept_ids.count LOOP
dept_names(inx1) := UPPER(dept_names(inx1) || '+');
DBMS_OUTPUT.PUT_LINE (dept_ids(inx1) || ' ' || dept_names(inx1));
END LOOP;

v_InsertStmt := 'UPDATE dept
SET dname = :1
WHERE deptno = :2';

FOR x IN dept_ids.first..dept_ids.last LOOP
EXECUTE IMMEDIATE v_InsertStmt USING IN dept_names(x), dept_ids(x);
END LOOP;

END;
/


3) FORALL 사용하기 : insert, update, delete 문과 사용

==> FORALL을 사용할 때, 문장은 모음의 각 항목에 대해 한번씩 실행된다.
하지만 PL/SQL에서 SQL로의 문맥전환은 오직 한번만 일어난다.
그 결과 PL/SQL에서 루프를 작성할 때보다 성능이 훨씬 빨라진다.

DECLARE
CURSOR all_depts IS
SELECT deptno, dname
FROM dept
ORDER BY dname;

TYPE dept_id IS TABLE OF dept.deptno%TYPE;
TYPE dept_name IS TABLE OF dept.dname%TYPE;

dept_ids dept_id;
dept_names dept_name;
inx1 PLS_INTEGER;

v_InsertStmt VARCHAR2(2000);

BEGIN
OPEN all_depts;
FETCH all_depts BULK COLLECT INTO dept_ids, dept_names;
CLOSE all_depts;

/** Load한 데이터의 변형 **/

FOR inx1 IN 1..dept_ids.count LOOP
dept_names(inx1) := UPPER(dept_names(inx1) || '+');
DBMS_OUTPUT.PUT_LINE (dept_ids(inx1) || ' ' || dept_names(inx1));
END LOOP;

FORALL x IN dept_ids.first..dept_ids.last
UPDATE dept
SET dname = dept_names(x)
WHERE deptno = dept_ids(x);

END;
/

SELECTS문에서 한번에 대량의 레코들 취득 하는 경우, BULK COLLECT구를 사용하면

한번에 여러개의 레코드를 취득할수 있으므로 퍼포먼스 향상

 

Patten 1

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

DECLARE
  TYPE empno_tbl_type IS TABLE OF EMP.EMPNO%TYPE INDEX BY BINARY_INTEGER;
  empno_tbl  empno_tbl_type;
BEGIN
  SELECT EMPNO BULK COLLECT INTO empno_tbl FROM EMP;
  IF empno_tbl.COUNT > 0 THEN
    FOR i IN empno_tbl.FIRST..empno_tbl.LAST LOOP
      UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = empno_tbl( i );
    END LOOP;
  END IF;
END;
/

 

Patten 2

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

DECLARE
  TYPE emp_tbl_type IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
  emp_tbl  emp_tbl_type;
BEGIN
  SELECT * BULK COLLECT INTO emp_tbl FROM EMP;
  IF emp_tbl.COUNT > 0 THEN
    FOR i IN emp_tbl.FIRST..emp_tbl.LAST LOOP
      UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = emp_tbl( i ).EMPNO;
    END LOOP;
  END IF;
END;
/

 

Patten 3 커서 이용

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

DECLARE
  CURSOR emp_cur IS
    SELECT * FROM EMP;
  TYPE emp_tbl_type IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;
  emp_tbl  emp_tbl_type;
BEGIN
  OPEN emp_cur;
  FETCH emp_cur BULK COLLECT INTO emp_tbl;
  CLOSE emp_cur;
  IF emp_tbl.COUNT > 0 THEN
    FOR i IN emp_tbl.FIRST..emp_tbl.LAST LOOP
      UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = emp_tbl( i ).EMPNO;
    END LOOP;
  END IF;
END;
/

 

즉,커서를 이용할시 취득할 데이터 수가 많을듯하면 Limit를 사용하여 일정 레코드 단위로

Fetch하는 것이 성능면에서 좋다.

 

FETCH emp_cur BULK COLLECT INTO emp_tbl LIMIT 100;

 

Posted by 농부지기
,

[ Oracle - Procedure 문법_FOR_SELECT문 ]

 

1. 문법 : FOR cur_item IN (select cd, txtn_yn, emp_yn, retro_yn

                                        from py_payitem_code a

                                        where a.idx_id = '2605'

                                        and a.type_cd = '지')

            LOOP

                       v_count := v_count + 1;

                       ............

            END LOOP;

Posted by 농부지기
,

[ Oracle - Procedure 문법_Cursor_SubQuery ]

 

Cursor_SubQuery 문

커서 서브 쿼리

 

커서 서브 쿼리는 Oracle8 이후부터 SQL 엔진에서 지원되어 온 기능이며, Oracle9i는 이러한 지원을  PL/SQL 엔진으로 확대하였습니다.  

커서 서브 쿼리는 커서 수식에 대한 매 평가마다 중첩된 커서를 오픈합니다.

부모 쿼리의 각각의 행에 대해, 해당 커서 수식에 대응하는 SELECT 리스트의 커서를 반환합니다.

서브 쿼리의 결과를 추출하기 위한 인출이 수행되어야 합니다.

 

사용)

PL/SQL에서, 커서 서브 쿼리는 다음과 같은 문맥에서 허용됩니다.

Ref 커서

명시적 커서

다음의 경우에는 허용되지 않습니다.

묵시적 커서

 

예: Ref 커서에서의 커서 서브 쿼리)

    DECLARE

        TYPE refcursortype IS REF CURSOR;

        n NUMBER;

        emprow employees%rowtype;

        empcur1 refcursortype;

        empcur2 refcursortype;

 

    BEGIN

        OPEN empcur1 FOR

            SELECT cursor(SELECT *

                              FROM   employees e

                              WHERE  d.deptno = e.deptno ), d.deptno

            FROM departments d;

        LOOP

            FETCH empcur1 INTO empcur2, n;

            LOOP

                FETCH empcur2 INTO emprow;

                …

            END LOOP;

        END LOOP;

        ...

    END;

 

예: 명시적 커서에 대한 커서 서브 쿼리)

    DECLARE

        TYPE refcursortype IS REF CURSOR;

        n NUMBER;

        emprow employees%rowtype;

        empcur1 refcursortype;

 

        CURSOR c1 is

            SELECT CURSOR ( SELECT *

                               FROM employees e

                                WHERE d.deptno = e.deptno ), d.deptno

            FROM departments d;

 

    BEGIN

        OPEN c1;

        LOOP        

            FETCH c1 INTO empcur1, n;

            ...

            LOOP

                FETCH empcur1 INTO emprow;

                  …

            END LOOP;

        END LOOP;

        ...

    END;

 

Posted by 농부지기
,

[ Oracle - Procedure 문법_Cursor_For ]

 

Cursor FOR문

--장점 : open, fetch 등을 하지 않아도 됨

--단점 : ??

--질문 : 만약, 한건도 없을 경우 for loop 가 수행 되는지 궁금??

 

CREATE OR REPLACE PROCEDURE HRMS.Op_Odm_Shift_Work_Daily_Update (

    in_yyyymm                           IN  VARCHAR2,   -- 작업년월

    in_emp_id           IN  VARCHAR2,   -- 사번

    in_apply_ym_m       IN  VARCHAR2,   -- 소급계산 처리시 수정처리년월

    in_mod_emp_id                    IN  VARCHAR2,   -- 작업자사번

    out_return                            OUT VARCHAR2    -- return 변수

)

IS

    CURSOR cur1 IS

        SELECT a.apply_ymd,

              a.shift_work_cd,

              a.data_type,

              a.sta_hm, a.end_hm

         FROM  ODM_SHIFT_WORK_DAILY a,

                      ODM_SHIFT_WORK_CODE b,

                    ODM_CALENDAR c

         WHERE a.shift_work_cd = b.cd

           AND     a.apply_ymd = c.cal_ymd

           AND    b.idx_id = '1109'

           AND    a.emp_id = in_emp_id

           AND    a.apply_ymd LIKE in_yyyymm || '%' ;

 

BEGIN

   ......

FOR eItem IN  cur1  LOOP

    ..........

 

   -- 이때 eItem 변수는 정의하지 않아도 사용가능하다.

    변수1 := eItem.apply_ymd;

    변수2 := eItem.shift_work_cd;

 

     .........

END LOOP;

    .........

END;

Posted by 농부지기
,

[ Oracle - Procedure 문법_Cursor_Fetch ]

 

CREATE OR REPLACE PROCEDURE HRMS.Op_Odm_Shift_Work_Daily_Update (

    in_yyyymm                           IN  VARCHAR2,   -- 작업년월

    in_emp_id           IN  VARCHAR2,   -- 사번

    in_apply_ym_m       IN  VARCHAR2,   -- 소급계산 처리시 수정처리년월

    in_mod_emp_id                    IN  VARCHAR2,   -- 작업자사번

    out_return                            OUT VARCHAR2    -- return 변수

)

IS

    CURSOR cur1 IS

        SELECT a.apply_ymd,

              a.shift_work_cd,

              a.data_type,

              a.sta_hm, a.end_hm

         FROM  ODM_SHIFT_WORK_DAILY a,

                      ODM_SHIFT_WORK_CODE b,

                       ODM_CALENDAR c

         WHERE a.shift_work_cd = b.cd

            AND     a.apply_ymd = c.cal_ymd

           AND    b.idx_id = '1109'

           AND    a.emp_id = in_emp_id

           AND    a.apply_ymd LIKE in_yyyymm || '%' ;

 

BEGIN

 

   --이때 cur1에 있는  in_emp_id 변수를 활용해서 sql 문이 실행 된다.

    OPEN cur1;

    LOOP

 

    FETCH cur1 INTO     v_f_apply_ymd,

            v_f_shift_work_cd,

            v_f_data_type,

            v_f_sta_hm,

            v_f_end_hm;

    EXIT WHEN cur1%NOTFOUND;

 

        ............... business logic ..........

    END LOOP;

    CLOSE cur1;

END;

 

 

Posted by 농부지기
,

[ Oracle - Procedure 문법 Cursor_Dynamic Fetch ]

 


설명 : - sql 문은 string 으로 생성 후 dynamic  loop를 돌린다.

         - dynamic cursor 에 대한 변수 선언 필요

문법 :

CREATE OR REPLACE procedure                HRMS.op_payroll_detail_mm_create(

    aRtn OUT       VARCHAR2 ) IS

    -- Cursor 선언

    TYPE   DYN_CURSOR_TYPE   IS REF CURSOR;

    DYN_CUR         DYN_CURSOR_TYPE;

 

BEGIN

   v_sqlsyntax := 'select a.pay_ymd, a.pay_type_cd, a.sta_ymd, a.end_ymd, a.pay_ym, a.duty_ym, a.give_ymd, a.calc_limit_yn

            from py_pay_ymd a,

            py_retroact b

            where a.pay_ymd = b.retro_pay_ymd

           and a.pay_type_cd = b.retro_pay_type_cd

           and b.emp_id = ''' || aEmp_id || ''' ';

 

   OPEN DYN_CUR FOR v_sqlsyntax;

   LOOP

 

   FETCH DYN_CUR INTO  sPay_ymd,

                sPay_type_cd,

                sSta_ymd,

                sEnd_ymd,

                sPay_ym,

                sDuty_ym,

                sGive_ymd,

                sCalc_limit_yn;

     EXIT WHEN DYN_CUR%NOTFOUND;

END;

Posted by 농부지기
,

[ Oracle - Procedure 문법_Cursor_02 ]

 

CURSOR 문

Explicit Cursors

 

1. Cursor

 

① Implicit cursor : PL/SQL이 정해 주는 것.

     SQL%NOTFOUND

     SQL%ISOPEN

     SQL%FOUND

     SQL%ROWCOUNT

 

 ② Expicit cursor : 응용 프로그래머에 의해서 어떤 동작을 수행하고자 할때 Explict cursor 를 사용하면

    buffer에 저장된다.

     Cursor_name%NOTFOUND

     Cursor_name%ISOPEN

     Cursor_name%FOUND

     Cussor_name%ROWCOUNT

 

2. Controlling Explicit cursors

  DECLARE OPEN FETCH EMPTY CLOSE

 

① Declaring the Cursor

  

   DECLARE

   CURSOR cursor_name IS

   select_statement;

 

② Opening the Cursor

      OPEN cursor_name;

 

③ Fetching Data from the Cursor

      FETCH cursor_name INTO variable1, variable2,....;

 

④ Closing the Cursor

     CLOSE cursor_name;

 

   ex) CREATE OR REPLACE PROCEDURE ord_process

           (v_ord_id IN s_item.ord_id%TYPE,

            v_message OUT VARCHAR2)

         IS

            v_product_id    s_item.product_id%TYPE;

            v_item_total    NUMBER(11,2);

            v_order_total   NUMBER(11,2) := 0;

            CURSOR item_cursor IS

              SELECT product_id, price * quantity

              FROM   s_item

              WHERE  ord_id = v_ord_id;

         BEGIN

            OPEN item_cursor;

            LOOP

               FETCH item_cursor INTO v_product_id, v_item_total;

               EXIT WHEN item_cursor%ROWCOUNT > 5

                 OR item_cursor%NOTFOUND;

               v_order_total := v_order_total + v_item_total;

               v_message := 'Product ID '||

                 TO_CHAR(v_product_id)||' has a total of '||

                 TO_CHAR(v_order_total,'$999,999,999.99');

            END LOOP;

            CLOSE item_cursor;

            COMMIT;

         END ord_process;

 

3. Cursor and Records (구조체?)

 

  ex) CURSOR emp_cursor IS

       SELECT id, salary, start_date, rowid

       FROM s_emp

       WHERE dept_id = 41;

          emp_record emp_cursor%ROWTYPE;

       BEGIN

      OPEN emp_cursor;

 

          ....

 

       FETCH emp_cursor INTO emp_record;

 

4. Cursor FOR Loops (open,fetch,close가 자동으로 수행됨)

    FOR record_name IN cursor_name LOOP

    statement1;

    statement2;

    ...

    END Loop;

  

  ex) FOR item_record IN item_cursor LOOP

           v_order_total := v_order_total +

           (item_record.price * item_record.quantity);

           i := i + 1;

           product_id_talble(1) := item_record.product_id;

           order_total_table(1) := v_order_total;

       END LOOP;

발주처 : http://myhome.netsgo.com/mino70/main_03_oracle02.htm

 

Posted by 농부지기
,

[ Oracle - Procedure 문법_Cursor_01 ]

 

declare

    x_sa_code    number;

    x_tax_io     number;

    x_io_date    date;

    x_io_no      number;

    x_tax_sno    number;

    CURSOR c_aaa is select distinct SA_CODE,TAX_IO,IO_DATE from ACC.TAX;

    CURSOR c_bbb is select TAX_SNO

                      from ACC.TAX

                     where SA_CODE=x_sa_code and TAX_IO=x_tax_io and IO_DATE=x_io_date;

begin

    open c_aaa;

 

    loop

        fetch c_aaa into x_sa_code,x_tax_io,x_io_date;

 

        exit when c_aaa%notfound;

 

        x_io_no:=0;

 

        open c_bbb;

        loop

                      c_bbb into x_tax_sno;

                      when c_bbb%notfound;

                      x_io_no:=x_io_no+1;

 

                      update ACC.TAX

                      set    IO_NO=x_io_no

              where  TAX_SNO=x_tax_sno;

        end loop;

 

        close c_bbb;

    commit;

 

    end loop;

    close c_aaa;

 

  exception

      when others then

         rollback;

         raise_application_error(-20001,sqlErrm(SqlCode));

end;

 

 

 

 

Posted by 농부지기
,