※ Oracle SID 확인
SQL> select instance from v$thread;

※ Oracle DB_NAME 확인
SQL> select name from v$database;

※ Oracle User 확인
SQL> select * from all_users;

※ 등록된 User 목록 보기
SQL> select username, user_id from dba_users order by username;

※ User가 소유한 모든 테이블 보기
SQL> select table_name from user_tables;

※ 사용자 정보 확인
SQL> select username, default_tablespace,temporary_tablespace from dba_users;

※ 오브젝트 조회
SQL> select * from all_objects where object_name like '명';

※ 테이블 조회
SQL> select * from all_tables where table_name like '명';

※ 시퀀스 정보 보기
SQL> select * from user_sequences;

※ 시노님 조회
SQL> select * from all_synonyms where synonym_name='명';

※ 테이블 인덱스 정보 조회
SQL> select * from all_ind_columns where table_name='테이블명';

※ 테이블의 컬럼 정보 조회
SQL> select * from all_tab_columns where table_name='테이블명';

※ table comment 쿼리
SQL> select * from all_tab_comments where table_name='테이블명';

※ column comment 쿼리
SQL> select * from all_col_comments where table_name='테이블명'


1. RAISE_APPLICATION_ERROR를 사용하여 오류코드 -20000부터 -20999의 범위 내에서 사용자 정의 예외를 만들 수 있다. 

- STEP 1: DECLARE  OR IS ... 예외의 이름을 선언 (선언절)

- STEP 2: RAISE문을 사용하여 직접적으로 예외를 발생시킨다. (실행절)

- STEP 3: 예외가 발생할 경우 해당 예외를 참조한다. (예외절)


ex) step 1: 예외의 이름을 선언 

sync_exec_day Exception;

V_SYNC_DAY VARCHAR2(4) := TO_CHAR(SYSDATE,'YD');


ex) step 2: RAISE 문을 사용하여 직접적으로 예외를 발생시킨다. 

IF V_SYNC_DAY IN ('목','일') THEN

RAISE sync_exec_day;

END IF;


ex) step 3: 예외가 발생할 경우 해당 예외를 참조한다.

EXCEPTION WHEN sync_exec_day THEN RAISE_APPLICATION_ERROR (-20001, '목,일요일에는 데이터를 갱신할 수 없습니다.' );


/* 예제 프로시저 */


SET SERVEROUTPUT ON;

DECLARE     

  V_SYNC_DAY   VARCHAR2(4) := TO_CHAR(SYSDATE,'DY');

  sync_exec_day EXCEPTION;  

BEGIN

  IF V_SYNC_DAY  IN ('토','일') THEN

    RAISE sync_exec_day ; 

  END IF;

  

  EXCEPTION

    WHEN sync_exec_day  THEN 

      RAISE_APPLICATION_ERROR(-20001,'토,일요일엔 데이터를 갱신할 수 없습니다.');

END;

/



1. ggusr 계정에 PR_EMP_TEST (프로시저)를 실행할 수 있는 권한을 부여하고  ggusr 세션에서 수행해보아라. 

1) 권한 부여하기 GRANT EXECUTE ON PR_EMP_TEST TO ggusr

2) SQL > connect ggusr/123123;

         SQL > EXEC PR_EMP_TEST;


2. AUTHID CURRENT USER

1) 더 엄격한 권한 관리가 가능하다. 

2) 프로시저를 실행할 수 있는 권한을 부여하더라도 TB_LS_EMP867 테이블을 조회할 수 있는 권한이 같이 부여되는 것은 아니다. 

즉,,

SQL > EXEC PR_EMP_TEST; ( 수행 O )

SQL > SELECT * FROM TB_LS-EMP867; ( 수행 X )


※ autonomous : 자율적인

PRAGMA : Compiler의 Preprocessor에게 지시/ 전달한다. 

In Oracle PL/SQL, PRAGMA refers to a compiler directive or "hint" it is used to provide an instruction to the compiler. The directive restricts member subprograms to query or modify database tables and packaged variables. Pragma directives are processed at compile time where they pass necessary information to the compiler; they are not processed at runtime.

The 5 types of Pragma directives available in Oracle are listed below:

  1. PRAGMA AUTONOMOUS_TRANSACTION: This pragma can perform an autonomous transaction within a PL/SQL block between a BEGIN and END statement without affecting the entire transaction.

  2. PRAGMA SERIALLY_REUSABLE: This directive tels Oracle that the package state is needed only for the duration of one call to the server. After the call is made the package may be unloaded to reclaim memory.

  3. PRAGMA RESTRICT_REFRENCES: Defines the purity level of a packaged program. After Oracle8i this is no longer required.

  4. PRAGMA EXCEPTION_INIT: This directive binds a user defined exception to a particular error number.

  5. PRAGMA INLINE: (Introduced in Oracle 11g) This directive specifies that a subprogram call either is or is not to be inlined. Inlining replaces a subprogram call with a copy of the called subprogram.


3.  PRAGMA AUTONOMOUS_TRANSACTION 을 가지고 독립 트랜잭션 제어

1) 다른 주 트랜잭션에 의해 시작되는 독립적인 트랜잭션이다. 

     .... 좀 더 공부하기..



4. 함수 생성 시, parallel enable 힌트를 사용하는 이유가 무엇인가?

 - 병렬 처리를 하게되면 데이터를 빨리 검색할 수 있다. 


5. 함수 생성 시, deterministic 절을 사용하는 이유는 ? 

 - 컬럼의 갯수만큼 실행된다.

 - deterministic을 써서 함수를 생성하면, 같은 값이 들어오면 함수를 실행하지 않고 데이터만 출력해준다. 




참조: www.grubee.net/lecture/1075


패키지(Package)는 오라클 데이터베이스에 저장되어 있는 서로 관련있는 PL/SQL 프로시저와 함수들의 집합이다.

패키지는 선언부와 본문 두 부분으로 나누어 진다. 


1. 패키지 선언절 문법


선언부

CREATE [ OR REPLACE ] PACKAGE  패키지명 IS AS 

[ 변수 선언절 ]

[ 커서 선언절 ]

[ 예외 선언절 ]

[ Procedure 선언절 ]

[ Function 선언절 ]

END 패키지명


- 선언절은 패키지에 포함될 PL/SQL 프로시저, 함수, 커서, 변수, 예약절을 선언한다. 

- 패키지 선언부에서 선언한 모든 요소들은 패키지 전체에 적용된다. 

- 즉, 선언부에서 선언한 변수는 PUBLIC 변수로 사용된다.



2. 패키지 본문 문법 


본문 

CREATE [ OR REPLACE ] PACKAGE BODY 패키지명 IS | AS

[ 변수 선언절 ]

[ 커서 선언절 ]

[ 예외 선언절 ]

[ Procedure 선언절 ]

[ Function 선언절 ]

END 패키지명


- 패키지 본문은 패키지에서 선언된 부분의 실행을 정의한다. 

- 즉 실제 프로시저나 함수의 내용에 해당하는 부분이 온다. 





3. 패키지 예제 


모든 사원의 사원 정보를 가져오는 프로시져 1개 ( 사번, 성명, 아이디, 부서번호, 급여 ) (BASIC..LOOP)


, 모든 사원의 사원 정보를 가져오는 프로시져 1개 ( 사번, 성명, 아이디, 부서번호, 급여 ) (WHILE..LOOP)


, 모든 사원의 급여 정보를 가져오는 프로시저 1개 ( 총급여, 평균급여, 최고급여, 최소급여 )


, 특정 부서의 사원 정보를 가져오는 프로시저 1개 ( 사번, 성명, 아이디, 부서번호, 급여 ) (FOR .. IN... LOOP)


, 특정 부서의 급여 정보를 가져오는 프로시저 1개 ( 총급여, 평균급여, 최고급여, 최소급여 )


총 5개의 프로시저를 만들어 패키지를 구성해 보아라. 





3-1 패키지 선언부 생성 예제 


CREATE OR REPLACE PACKAGE EMP_PKG 


AS 

-- IS 로 해도되지만 본문에서 각각의 프로시저를 정의할 때 

-- 해당 프로시저의 선언문을 IS로 사용하기 때문에 난 AS로 사용한다. 

-- 헷갈리지 않게 하기 위해서 


PROCEDURE ALL_EMP_INFO; -- BASIC .. LOOP

PROCEDURE ALL_EMP_INFO_2; -- WHILE .. LOOP

PROCEDURE ALL_EMP_SAL;

PROCEDURE SPC_DEPT_EMP_INFO (P_DEPT_NO IN NUMBER); -- FOR .. IN .. LOOP

PROCEDURE SPC_DEPT_EMP_SAL (P_DEPT_NO IN NUMBER);


END EMP_PKG;

-- 패키지만들때는 / 이거 놓치지말자.



3-2 패키지 본문 생성 예제 


CREATE OR REPLACE PACKAGE BODY EMP_PKG

AS


    PROCEDURE ALL_EMP_INFO  

    IS

        CURSOR EMP_CURSOR 

        IS

        SELECT EMP_NO, EMP_NM, EMP_ID, DEPT_NO, SAL

        FROM TB_LS_EMP867;

        

        -- 변수를 선언한다.

        V_EMP_NO NUMBER(8) := 0;

        V_EMP_NM VARCHAR2(20);

        V_EMP_ID VARCHAR2(30);

        V_DEPT_NO NUMBER(4) := 0;

        V_SAL NUMBER(10) := 0;

      

    BEGIN

      

      -- CURSOR, BASIC LOOP 사용

      OPEN EMP_CURSOR ;

        LOOP

          FETCH EMP_CURSOR INTO V_EMP_NO, V_EMP_NM, V_EMP_ID, V_DEPT_NO, V_SAL;

          EXIT WHEN EMP_CURSOR%NOTFOUND;

          DBMS_OUTPUT.PUT_LINE(V_EMP_NM || '님의 레코드는 다음과 같습니다. : ' 

|| V_DEPT_NO || ' | ' || V_EMP_NM || ' | ' || V_EMP_ID || ' | ' || V_DEPT_NO || ' | ' || V_SAL );

        END LOOP;

      CLOSE EMP_CURSOR ;

      

      EXCEPTION WHEN OTHERS THEN SYS.DBMS_OUTPUT.PUT_LINE ('Error Number:::' || SQLERRM );

      

    END;

    

    PROCEDURE ALL_EMP_INFO_2 

    IS

        CURSOR EMP_CURSOR 

        IS

        SELECT EMP_NO, EMP_NM, EMP_ID, DEPT_NO, SAL

        FROM TB_LS_EMP867;

        

        -- 변수를 선언한다.

        V_EMP_NO NUMBER(8) := 0;

        V_EMP_NM VARCHAR2(20);

        V_EMP_ID VARCHAR2(30);

        V_DEPT_NO NUMBER(4) := 0;

        V_SAL NUMBER(10) := 0;

      

    BEGIN

      

      -- CURSOR, WHILE LOOP

      OPEN EMP_CURSOR;

        FETCH EMP_CURSOR INTO V_EMP_NO, V_EMP_NM, V_EMP_ID, V_DEPT_NO, V_SAL;

        WHILE EMP_CURSOR%FOUND LOOP

          DBMS_OUTPUT.PUT_LINE(V_EMP_NM || '님의 레코드는 다음과 같습니다. : '

 || V_DEPT_NO || ' | ' || V_EMP_NM || ' | ' || V_EMP_ID || ' | ' || V_DEPT_NO || ' | ' || V_SAL );

          FETCH EMP_CURSOR INTO V_EMP_NO, V_EMP_NM, V_EMP_ID, V_DEPT_NO, V_SAL;

        END LOOP;

      CLOSE EMP_CURSOR;

      

      EXCEPTION WHEN OTHERS THEN SYS.DBMS_OUTPUT.PUT_LINE ('Error Number:::' || SQLERRM );

      

    END;

  

    PROCEDURE ALL_EMP_SAL

    IS 

        V_TOT_SAL NUMBER(12) := 0;

        V_MAX_SAL NUMBER(12) := 0;

        V_MIN_SAL NUMBER(12) := 0;

        V_AVG_SAL NUMBER(12) := 0;

        

    BEGIN

        SELECT SUM(SAL), MAX(SAL), MIN(SAL), AVG(SAL) 

        INTO V_TOT_SAL, V_MAX_SAL, V_MIN_SAL, V_AVG_SAL

        FROM TB_LS_EMP867;

        DBMS_OUTPUT.PUT_LINE('총급여: '|| V_TOT_SAL ||'/ 최대급여: '|| V_MAX_SAL||'/ 최소급여: '|| V_MIN_SAL ||'/ 평균급여: '|| V_AVG_SAL);

        

        EXCEPTION WHEN OTHERS THEN SYS.DBMS_OUTPUT.PUT_LINE ('Error Number:::' || SQLERRM );

        

    END;

    

    -- CURSOR, FOR ..IN .. LOOP 사용

    PROCEDURE SPC_DEPT_EMP_INFO(P_DEPT_NO IN NUMBER)

    

    IS

        CURSOR EMP_CURSOR 

        IS

        SELECT EMP_NO, EMP_NM, EMP_ID, DEPT_NO, SAL

        FROM TB_LS_EMP867

        WHERE DEPT_NO = P_DEPT_NO;

    BEGIN 

        

        FOR EMP_RECORD IN  EMP_CURSOR LOOP

          DBMS_OUTPUT.PUT_LINE(EMP_RECORD.EMP_NM || '님의 레코드는 다음과 같습니다. : '

    || EMP_RECORD.DEPT_NO || ' | ' || EMP_RECORD.EMP_ID || ' | ' || EMP_RECORD.DEPT_NO || ' | ' || EMP_RECORD.SAL );

        END LOOP;

        

        EXCEPTION WHEN OTHERS THEN SYS.DBMS_OUTPUT.PUT_LINE ('Error Number:::' || SQLERRM );

        

    END;

    

    -- 동적 SQL 사용

    PROCEDURE SPC_DEPT_EMP_SAL (P_DEPT_NO IN NUMBER)

    IS 

        V_DEPT_NO NUMBER(4) := 0;

        V_TOT_SAL NUMBER(12) := 0;

        V_MAX_SAL NUMBER(12) := 0;

        V_MIN_SAL NUMBER(12) := 0;

        V_AVG_SAL NUMBER(12) := 0;


        V_STMT VARCHAR2(200);

        

    BEGIN 

        

        V_STMT := 'SELECT SUM(SAL), MAX(SAL), MIN(SAL), AVG(SAL) FROM TB_LS_EMP867 WHERE DEPT_NO = :BUSEO_NUM GROUP BY 

DEPT_NO' ;

        EXECUTE IMMEDIATE V_STMT

        INTO V_TOT_SAL, V_MAX_SAL, V_MIN_SAL, V_AVG_SAL

        USING P_DEPT_NO;

        DBMS_OUTPUT.PUT_LINE('총급여: '|| V_TOT_SAL ||'/ 최대급여: '|| V_MAX_SAL||'/ 최소급여: '|| V_MIN_SAL ||'/ 평균급여: '|| V_AVG_SAL);

        

        EXCEPTION WHEN OTHERS THEN SYS.DBMS_OUTPUT.PUT_LINE ('Error Number:::' || SQLERRM );

        

    END;

    -- CURSOR, BASIC LOOP 사용

END EMP_PKG;




3-3 패키지 실행


- 패키지의 실행은 패키지명 (ex : EMP_PKG) 다음에 점(.)을 찍고 프로시저나 함수 명을 적어주면 된다. 


SET SERVEROUTPUT ON;

-- 패키지 실행 


SQL > EXEC EMP_PKG.ALL_EMP_INFO;

SQL > EXEC EMP_PKG.ALL_EMP_INFO_2;

SQL > EXEC EMP_PKG.ALL_EMP_SAL;

SQL > EXEC EMP_PKG.SPC_DEPT_EMP_INFO (P_DEPT_NO IN NUMBER);

SQL > EXEC EMP_PKG.SPC_DEPT_EMP_SAL (P_DEPT_NO IN NUMBER);

create or replace PROCEDURE PR_POPULAR_MOVE_INTO_RCMD


(P_USER_NO NUMBER)


IS

    CURSOR RCMD_CURSOR IS 

        SELECT Y.RO, SUBSTR(Y.CRS_SESS_ID,1,7) CRS_ID, Y.CRS_SESS_ID, Y.WR_DTM

        FROM(

            SELECT ROWNUM RO, X.*

            FROM (

                  SELECT *

                  FROM TB_ST_CRS_STTS_DAY 

                  WHERE RCMD_KIND_CD = '2' 

                  AND WR_PER_NO = P_USER_NO

                  ORDER BY RCMD_DT, SORT_OR

                )X

           )Y 

      WHERE Y.RO <= 12;

           

    V_SORT_OR NUMBER(5) := 0;

    V_CRS_ID VARCHAR2(10);

    V_CRS_SESS_ID VARCHAR2(20);

    V_RCMD_DTM VARCHAR2(14);

    V_STMT VARCHAR2(200);

    V_CNT NUMBER(4);

    

-- BASIC LOOP 사용    

BEGIN

    /* 오늘 반영한 데이터가 있는지 조회 Start 

       동적 SQL 적용 (그룹함수 사용가능하다) */

    V_STMT :=

    'SELECT COUNT(CRS_ID) FROM TB_LS_CRS_RCMD 

WHERE USER_NO = 15771499 

AND SUBSTR(RCMD_DTM,1,8)  = TO_CHAR(SYSDATE,''YYYYMMDD'')';

    

    EXECUTE IMMEDIATE V_STMT

    INTO V_CNT;

    

    DBMS_OUTPUT.PUT_LINE('V_CNT:::'||V_CNT);

    /* End */

    

    IF V_CNT = 0 THEN

      OPEN RCMD_CURSOR;

        LOOP

          FETCH RCMD_CURSOR INTO V_SORT_OR, V_CRS_ID, V_CRS_SESS_ID, V_RCMD_DTM;

          -- EXIT의 위치는 반드시 여기로 (원하는 로직:INSERT 위)! 안그러면 Error발생한다.

          -- 무결성제약조건위배 :WHY? 마지막행이 중복실행되므로

          EXIT WHEN RCMD_CURSOR%NOTFOUND; 

          

--          DBMS_OUTPUT.PUT_LINE('=============================');

--          DBMS_OUTPUT.PUT_LINE('V_SORT_OR::'|| V_SORT_OR);

--          DBMS_OUTPUT.PUT_LINE('V_CRS_ID::'|| V_CRS_ID);

--          DBMS_OUTPUT.PUT_LINE('V_CRS_SESS_ID::'|| V_CRS_SESS_ID);

--          DBMS_OUTPUT.PUT_LINE('V_RCMD_DTM::'|| V_RCMD_DTM);

--          DBMS_OUTPUT.PUT_LINE('=============================');

          

--          DBMS_OUTPUT.PUT_LINE('INSERT INTO TB_LS_CRS_RCMD VALUES (15771499,' || V_CRS_ID || ', 04 , 15771499,' || V_CRS_SESS_ID || ', ,' || 

V_RCMD_DTM || ', 15771499 ,' || TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS') || ',2,' || V_SORT_OR || ')');

          INSERT INTO TB_LS_CRS_RCMD VALUES (15771499, V_CRS_ID, '04' , 15771499 , V_CRS_SESS_ID, '', V_RCMD_DTM, 15771499, 

TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS'), '2', V_SORT_OR);

        

        END LOOP;

      CLOSE RCMD_CURSOR;

    ELSE DBMS_OUTPUT.PUT_LINE('데이터가 이미 삽입되어있습니다.'); ROLLBACK;

    END IF;

    

    COMMIT;  -- 예외처리 전에 반드시 커밋을해야한다. 

    

    EXCEPTION

      WHEN OTHERS THEN

        DBMS_OUTPUT.PUT_LINE('Error Number: ' ||SQLERRM);

        ROLLBACK;

       

END;

+ Recent posts