DATA 전문가로 가는 길

[SQL] 오라클(Oracle) External Table Auto Script(자동 생성기) 본문

Data Architecture/SQL Query

[SQL] 오라클(Oracle) External Table Auto Script(자동 생성기)

EstenPark 2013. 11. 21. 15:02

보통 인터페이스에서 수신받은 데이터를 일괄적으로 테이블에 쌓는 작업을 많이 하게 되는데 그때 필요한 작업이 SQL Loader, 자바, C에서 로딩하는 여러 가지 방식이 있을 수 있습니다. 그러나 소스코딩이 많아서 업로딩 할 때 시간이 많이 들기 때문에 Oracle에서 추천하는 External Table을 이용하여 파일을 빠르게 로딩할 수 있습니다. 대량의 데이터를 업로딩 해보지 않았지만 500MB 파일을 로딩하는 데 큰 문제는 없었습니다.

 

다만, External Table -> 일반 적재 테이블 -> 서비스될 테이블 순으로 변경 절차가 많아진다는 단점은 보입니다. 그러나 DB 설계 시 표준화 작업을 제대로 했다면 위와 같은 일괄작업을 손쉽게 할 수 있습니다.

 

그럼 External Table(익스터널 테이블) 자동 생성 PL/SQL을 보여드리겠습니다.

 

PL/SQL 쿼리

 

DECLARE
   V_OWNER          VARCHAR2(30);
   V_TABLE_NM       VARCHAR2(30);
   V_DIC_DRY        VARCHAR2(50);
   V_FILE_EXEC      VARCHAR2(30);
   V_TABLE_GB       VARCHAR2(1);
BEGIN
   
  V_OWNER           := 'TESTDBA';         -- 스키마 명
  V_TABLE_GB        := 'T';               -- T : 하나의 테이블, A : 모든 테이블
  V_TABLE_NM        := 'FODTS002NT';      -- TABLE 명    
  V_DIC_DRY         := 'EXT_DIR';         -- 로컬 디렉토리 명
  V_FILE_EXEC       := 'dat';             -- 파일 확장자 명
  
  DECLARE CURSOR C IS
    -- 오라클을 이용하여 External Table 생성 초기 쿼리를 만든다.
    -- V_TABLE_GB = 'A' 는 사용하지 말 것.
    SELECT  
             A.OWNER
            ,A.TABLE_NAME
            ,A.COLUMN_NAME
            ,A.DATA_TYPE
            ,A.COLUMN_ID
            ,A.LAST_COLUMN_ID
    FROM     (
             SELECT 
                    A.OWNER
                   ,A.TABLE_NAME
                   ,A.COLUMN_NAME
                   ,DECODE(A.DATA_TYPE, 'VARCHAR2', A.DATA_TYPE||'('||A.DATA_LENGTH||')', 
                                        'NUMBER'  , A.DATA_TYPE||'('||A.DATA_PRECISION||', '||A.DATA_SCALE||')' ) AS DATA_TYPE
                   ,A.COLUMN_ID AS COLUMN_ID
                   ,LAST_VALUE(A.COLUMN_ID) OVER (PARTITION BY A.TABLE_NAME ORDER BY A.COLUMN_ID 
                                                  RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS LAST_COLUMN_ID -- 테이블 컬럼ID 중에서 최고 값
             FROM   DBA_TAB_COLUMNS A
             WHERE  A.OWNER      = V_OWNER
             AND    (V_TABLE_GB = 'T' AND A.TABLE_NAME  = V_TABLE_NM      /* 특정 테이블에 대해서 만들 경우 */
                     OR
                     V_TABLE_GB = 'A' AND A.TABLE_NAME IN (SELECT    S.TABLE_NAME /* 유저에 있는 모든 테이블을 기준으로 생성 */
                                                            FROM     DBA_TABLES S
                                                            WHERE    S.OWNER = V_OWNER)              
                     )
             AND    A.COLUMN_NAME NOT IN ('ALTR_PSN_ID', 'ALTR_DTTM')
             ) A
    ORDER  BY A.TABLE_NAME, A.COLUMN_ID ;
   
  BEGIN
    -- Oracle External Table Script 시작
    DBMS_OUTPUT.PUT_LINE('CREATE TABLE '|| V_OWNER ||'.EXT_'||V_TABLE_NM );
    DBMS_OUTPUT.PUT_LINE('(');
     FOR CTL_LIST IN C LOOP
       -- SQL*Loader  Control File 형식에 해당하는 콤마(,)를 마지막에는 제거 함.
       IF CTL_LIST.COLUMN_ID <> CTL_LIST.LAST_COLUMN_ID THEN 
         DBMS_OUTPUT.PUT_LINE( '    ' || CTL_LIST.COLUMN_NAME || '    ' || CTL_LIST.DATA_TYPE || ',' );
       ELSE
         DBMS_OUTPUT.PUT_LINE( '    ' || CTL_LIST.COLUMN_NAME || '    ' || CTL_LIST.DATA_TYPE );
       END IF;        
     END LOOP;
    DBMS_OUTPUT.PUT_LINE(')                                                    ');
    DBMS_OUTPUT.PUT_LINE('ORGANIZATION EXTERNAL');
    DBMS_OUTPUT.PUT_LINE('  (  TYPE ORACLE_LOADER');
    DBMS_OUTPUT.PUT_LINE('     DEFAULT DIRECTORY '||V_DIC_DRY);
    DBMS_OUTPUT.PUT_LINE('     ACCESS PARAMETERS');
    DBMS_OUTPUT.PUT_LINE('       ( RECORDS DELIMITED BY NEWLINE');
    DBMS_OUTPUT.PUT_LINE('         NOBADFILE');
    DBMS_OUTPUT.PUT_LINE('         NODISCARDFILE');
    DBMS_OUTPUT.PUT_LINE('         NOLOGFILE');
    DBMS_OUTPUT.PUT_LINE('         FIELDS TERMINATED BY '||''''||'|'||'''');
    DBMS_OUTPUT.PUT_LINE('         MISSING FIELD VALUES ARE NULL     )');
    DBMS_OUTPUT.PUT_LINE('     LOCATION ('||V_DIC_DRY||':'||''''||V_TABLE_NM||'.'||V_FILE_EXEC||''')');    
    DBMS_OUTPUT.PUT_LINE('  )');
    DBMS_OUTPUT.PUT_LINE('REJECT LIMIT UNLIMITED');
    DBMS_OUTPUT.PUT_LINE('NOPARALLEL');
    DBMS_OUTPUT.PUT_LINE('NOMONITORING;');
  END; 

EXCEPTION
   WHEN NO_DATA_FOUND THEN
      NULL;
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('ERROR');
      NULL;
END;


Comments