--公司最近作數據集市DM建模 我把我這部分貼出來供你們參考 還請批評指正2016-02-22函數
--本文涉及Oracle的基礎語法等再也不贅述spa
DECLARE T_TABLE_NAME varchar2(20) := 'DM_R3G_$YYYYMM'; --表名DM_R3G_INFO_$YYYYMM T_TIMEST VARCHAR2(8) := '20160218'; --20160218 T_OPER_NO VARCHAR2(20); --申請人工號 T_IP VARCHAR2(20); --申請人IP 127.0.0.1 IS_EXISTS NUMBER; --分區表是否存在 T_YEAR VARCHAR2(4); -- T_MONTH VARCHAR2(2); -- T_DAY VARCHAR2(2); -- T_YEAR_MONTH VARCHAR2(6); -- T_DATA_SOURCE VARCHAR2(50); --R3G_INFO_DAY@LINK_FSDB T_DATA_FILTER VARCHAR2(100); --TIMEST = TO_DATE('$YYYYMMDD', 'YYYYMMDD') T_CREATE_MODE VARCHAR2(10); --獲取模式 003-年按月分區 004-月按日分區 T_PARTITION_NUM NUMBER; type TYPE_CUR IS REF CURSOR; --用引用遊標添加分區表DM_R3G_INFO_201602的columns CUR_TABLE_COLS TYPE_CUR; T_COLUMN_NAME ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;--引用類型 T_DATA_TYPE ALL_TAB_COLUMNS.DATA_TYPE%TYPE; T_DATA_LENGTH ALL_TAB_COLUMNS.DATA_LENGTH%TYPE; T_COL_INFO VARCHAR2(50); IS_COL_IN_TABLE NUMBER := 0; T_INSERT_COLS VARCHAR2(8000); BEGIN --第一步 --SELECT * FROM DM_CODE_TABLE A WHERE A.TABLE_NAME = 'DM_R3G_INFO_$YYYYMM'; BEGIN SELECT DATA_SOURCE, DATA_FILTER, CREATE_MODE INTO T_DATA_SOURCE, T_DATA_FILTER, T_CREATE_MODE FROM DM_CODE_TABLE@fs_dbcenter T WHERE T.TABLE_NAME = T_TABLE_NAME; EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20000,'表名' || TRIM(T_TABLE_NAME) || '無效'); END; --日期處理,把T_TIMEST轉成YYYYMM YYYY MM T_YEAR_MONTH := TO_CHAR(TO_DATE(T_TIMEST, 'YYYYMMDD'), 'YYYYMM'); T_YEAR := TO_CHAR(TO_DATE(T_TIMEST, 'YYYYMMDD'), 'YYYY'); T_MONTH := TO_CHAR(TO_DATE(T_TIMEST, 'YYYYMMDD'), 'MM'); T_DAY := TO_CHAR(TO_DATE(T_TIMEST, 'YYYYMMDD'), 'DD'); --變量替換 T_TABLE_NAME := REPLACE(T_TABLE_NAME, '$YYYYMM', T_YEAR_MONTH); --DM_R3G_INFO_201602 T_TABLE_NAME := REPLACE(T_TABLE_NAME, '$YYYY', T_YEAR); T_TABLE_NAME := REPLACE(T_TABLE_NAME, '$MM', T_MONTH); T_DATA_FILTER := REPLACE(T_DATA_FILTER, '$YYYYMMDD', T_TIMEST); T_DATA_FILTER := REPLACE(T_DATA_FILTER, '$YYYYMM', T_YEAR_MONTH); T_DATA_FILTER := REPLACE(T_DATA_FILTER, '$YYYY', T_YEAR); T_DATA_FILTER := REPLACE(T_DATA_FILTER, '$MM', T_MONTH); T_DATA_SOURCE := REPLACE(T_DATA_SOURCE, '$YYYYMM', T_YEAR_MONTH); T_DATA_SOURCE := REPLACE(T_DATA_SOURCE, '$YYYY', T_YEAR); T_DATA_SOURCE := REPLACE(T_DATA_SOURCE, '$MM', T_MONTH); --第二步 建立數據臨時表 P_DROP_TABLE('TMP_' || T_TABLE_NAME);--封裝的函數,用途drop table XXX purge --拼SQL,把數據放臨時表 EXECUTE IMMEDIATE 'CREATE TABLE TMP_' || T_TABLE_NAME || ' NOLOGGING AS SELECT * FROM ' || T_DATA_SOURCE || ' A ' || (CASE WHEN TRIM(T_DATA_FILTER) IS NOT NULL THEN ' WHERE ' || TRIM(T_DATA_FILTER) ELSE NULL END); --判斷建立模式 --第三步:一、判斷表是否存在,若是不存在,建立一個空表先 SELECT COUNT(1) INTO IS_EXISTS FROM ALL_TABLES A WHERE A.TABLE_NAME = T_TABLE_NAME AND A.OWNER = USER; --若是表不存在建立分區表 IF IS_EXISTS = 0 THEN if T_CREATE_MODE = '003' THEN T_PARTITION_NUM := 12; ELSIF T_CREATE_MODE = '004' THEN T_PARTITION_NUM := 31;--模式003建立12個月分區,模式004建立31個日分區 END IF; EXECUTE IMMEDIATE ' CREATE TABLE ' || T_TABLE_NAME || ' ( P_ID VARCHAR2(2) ) PARTITION BY LIST (P_ID) ( PARTITION ' || T_TABLE_NAME || '_P01 VALUES (''01'') )';--建立分區列P_ID FOR T_TMP_I IN 2 .. T_PARTITION_NUM LOOP EXECUTE IMMEDIATE ' ALTER TABLE ' || T_TABLE_NAME || ' ADD PARTITION ' || T_TABLE_NAME || '_P' || LPAD(T_TMP_I, 2, '0') || ' VALUES(''' || LPAD(T_TMP_I, 2, '0') || ''')'; END LOOP;--循環建立分區 OPEN CUR_TABLE_COLS FOR 'SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH FROM ALL_TAB_COLUMNS A WHERE A.OWNER = ''' || user || ''' AND A.TABLE_NAME = ''TMP_' || T_TABLE_NAME || ''' AND COLUMN_NAME != ''P_ID'''; LOOP EXIT WHEN CUR_TABLE_COLS%NOTFOUND; FETCH CUR_TABLE_COLS INTO T_COLUMN_NAME, T_DATA_TYPE, T_DATA_LENGTH; --IS_COL_IN_TABLE /*EXECUTE IMMEDIATE 'SELECT SUM(CASE WHEN COLUMN_NAME = ' || T_COLUMN_NAME || ' THEN 1 OTHERS THEN 0 END) WHERE A.OWNER = ''' || user || ''' AND A.TABLE_NAME = ' || T_TABLE_NAME || ' GROUP BY TABLE_NAME ' INTO IS_COL_IN_TABLE; IF IS_COL_IN_TABLE = 0 THEN SELECT T_COLUMN_NAME || ' ' || T_DATA_TYPE || DECODE(T_DATA_TYPE, 'VARCHAR2', '(' || T_DATA_LENGTH || ')', '') INTO T_COL_INFO FROM DUAL; EXECUTE IMMEDIATE 'ALTER TABLE ' || T_TABLE_NAME || ' ADD (' || T_COL_INFO || ')'; ELSE NULL; END IF;*/ --不存在的列都插入,此爲拓展功能,若源表增長列時使用 SELECT T_COLUMN_NAME || ' ' || T_DATA_TYPE || DECODE(T_DATA_TYPE, 'VARCHAR2', '(' || T_DATA_LENGTH || ')', '') INTO T_COL_INFO FROM DUAL; EXECUTE IMMEDIATE 'ALTER TABLE ' || T_TABLE_NAME || ' ADD (' || T_COL_INFO || ')'; --IS_COL_IN_TABLE := 0; END LOOP; CLOSE CUR_TABLE_COLS; --遊標結束,分區表的列已所有建立 END IF; /*清空分區*/ EXECUTE IMMEDIATE 'ALTER TABLE ' || T_TABLE_NAME || ' TRUNCATE PARTITION ' || T_TABLE_NAME || '_P' || (CASE WHEN T_CREATE_MODE = '003' THEN LPAD(T_DAY, 2, '0') WHEN T_CREATE_MODE = '004' THEN LPAD(T_MONTH, 2, '0') END) || ' UPDATE GLOBAL INDEXES';--這裏必須更新全局索引,由於表的每一個分區能夠視爲獨立的表,都要更新索引 SELECT WM_CONCAT(A.COLUMN_NAME) INTO T_INSERT_COLS FROM ALL_TAB_COLS A WHERE A.TABLE_NAME = 'TMP_' || T_TABLE_NAME AND A.OWNER = USER AND A.COLUMN_NAME != 'P_ID';--搜索全部列名,並concat鏈接後賦值給T_INSERT_COLS變量 --正式保存數據 execute immediate ' INSERT INTO ' || T_TABLE_NAME || ' PARTITION(' || T_TABLE_NAME || '_P' || (CASE WHEN T_CREATE_MODE = '003' THEN LPAD(T_DAY, 2, '0') WHEN T_CREATE_MODE = '004' THEN LPAD(T_MONTH, 2, '0') END) || ') NOLOGGING (P_ID, ' || T_INSERT_COLS || ')--此處注意NOLOGGING的位置,放在PARTITION後,列名前 select ''' || (CASE WHEN T_CREATE_MODE = '003' THEN LPAD(T_DAY, 2, '0') WHEN T_CREATE_MODE = '004' THEN LPAD(T_MONTH, 2, '0') END) || ''' P_ID, ' || T_INSERT_COLS || ' from TMP_' || T_TABLE_NAME; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_LINE(SQLCODE || ':' || SQLERRM); END;