http://sosuny.iteye.com/blog/551006
一、Oracle臨時表知識
在Oracle中,臨時表分爲SESSION、TRANSACTION兩種,SESSION級的臨時表數據在整個SESSION都存在,直到結束此次SESSION;而 TRANSACTION級的臨時表數據在TRANACTION結束後消失,即COMMIT/ROLLBACK或結束SESSION都會清除 TRANACTION臨時表數據。
1) 會話級臨時表 示例
1創建
- create global temporary table temp_tbl(col_a varchar2(30))
- on commit preserve rows
2插入數據
- insert into temp_tbl values('test session table')
3提交
- commit;
4查詢
- select *from temp_tbl
可以看到數據'test session table'記錄還在。
結束SESSION,重新登錄,再查詢數據select *from temp_tbl,這時候記錄已不存在,因爲系統在結束SESSION時自動清除記錄 。
2) 事務級臨時表 示例
1創建
- create global temporary table temp_tbl(col_a varchar2(30))
- on commit delete rows
2插入數據
- insert into temp_tbl values('test transaction table')
3提交
- commit ;
4查詢
- select *from temp_tbl
這時候可以看到剛纔插入的記錄'test transaction table'已不存在了,因爲提交時已經晴空了數據庫;同樣,如果不提交而直接結束SESSION,重新登錄記錄也不存在 。
二、在Oracle存儲中使用臨時表的一個例子
描述:檔案冊借閱時,需要把冊拆分成詳細的單據,拆分依據是冊表中的BILLCODES(若干個用逗號分割的單據號)字段,臨時表用於保存拆分出來的單據信息。拆分結束後直接返回臨時表的數據。
- create or replace package AMS_PKG as
- type REFCURSORTYPE is REF CURSOR;
- procedure SPLIT_VOLUMES (P_CORP_NAME IN varchar2,P_YEAR IN varchar2,P_MONTH IN varchar2,P_VOL_TYPE_CODE IN varchar2,P_BILL_NUM IN varchar2,P_VOLUME_NUM IN varchar2,P_AREA_CODES IN varchar2,P_QUERY_SQL out varchar2,P_OUTCURSOR out refCursorType);
- end AMS_PKG;
- /
- CREATE OR REPLACE PACKAGE BODY "AMS_PKG" as
- procedure SPLIT_VOLUMES(p_CORP_NAME IN varchar2, --查詢條件,公司名稱
- p_YEAR IN varchar2, --查詢條件,會計年度
- p_MONTH IN varchar2, --查詢條件,期間
- p_VOL_TYPE_CODE IN varchar2, --查詢條件,憑證類別編碼
- p_BILL_NUM IN varchar2, --查詢條件,信息單號
- p_VOLUME_NUM IN varchar2, --查詢條件,冊號
- p_AREA_CODES IN varchar2, --查詢條件,所在區域編碼(產生冊的區域),逗號分割。
- --形式如 '12C01','12201','12D01','12E01','12601',存儲過程中將使用in的方式進行過濾
- p_QUERY_SQL out varchar2, --返回查詢字符串
- p_OutCursor out refCursorType --返回值
- ) is
- v_sql varchar2(3000);
- v_sql_WHERE varchar2(3000);
- v_temp1 varchar2(300);
- v_temp2 varchar2(300);
- v_tempBILLCODES varchar2(3000);
- V_CNT NUMBER(10,0);
- V_VOLUME_ID NUMBER(10,0);
- mycur refCursorType;
- --CURSOR mycur( v varchar2) is
- -- SELECT VOUCHTYPE,BILLCODES FROM PUB_VOLUMES where volumeid=v;
- CURSOR mycur_split( val varchar2,splitMark varchar2) is
- select * from table(myutil_split(val,splitMark));
- begin
- v_temp1 :='';
- v_temp2 :='';
- v_sql_WHERE := '';
- v_tempBILLCODES := '';
- V_CNT := 0;
- V_VOLUME_ID := 0;--冊表的系統編號
- v_sql := 'SELECT VOLUMEID,VOUCHTYPE,BILLCODES FROM PUB_VOLUMES WHERE 1=1 ';
- --dbms_output.put_line('p_BILL_NUM='||p_BILL_NUM);
- IF (p_CORP_NAME IS NOT NULL AND LENGTH(p_CORP_NAME) >0) THEN --公司名稱
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND CORPNAME LIKE ''%';
- v_sql_WHERE := v_sql_WHERE || p_CORP_NAME;
- v_sql_WHERE := v_sql_WHERE || '%''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- IF (p_YEAR IS NOT NULL AND LENGTH(p_YEAR) >0) THEN --會計年度
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND YEAR = ''';
- v_sql_WHERE := v_sql_WHERE || p_YEAR;
- v_sql_WHERE := v_sql_WHERE || '''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- IF (p_MONTH IS NOT NULL AND LENGTH(p_MONTH) >0) THEN --期間
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND MONTH = ''';
- v_sql_WHERE := v_sql_WHERE || p_MONTH;
- v_sql_WHERE := v_sql_WHERE || '''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- IF (p_VOL_TYPE_CODE IS NOT NULL AND LENGTH(p_VOL_TYPE_CODE) >0) THEN --憑證類別編碼
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND VOUCHTYPE = ''';
- v_sql_WHERE := v_sql_WHERE || p_VOL_TYPE_CODE;
- v_sql_WHERE := v_sql_WHERE || '''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- IF (p_BILL_NUM IS NOT NULL AND LENGTH(p_BILL_NUM) >0) THEN --信息單號
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND BILLCODES LIKE ''%';
- v_sql_WHERE := v_sql_WHERE || p_BILL_NUM;
- v_sql_WHERE := v_sql_WHERE || '%''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- IF (p_VOLUME_NUM IS NOT NULL AND LENGTH(p_VOLUME_NUM) >0) THEN --冊號
- BEGIN
- v_sql_WHERE := v_sql_WHERE || ' AND VOLUMENUM = ''';
- v_sql_WHERE := v_sql_WHERE || p_VOLUME_NUM;
- v_sql_WHERE := v_sql_WHERE || '''';
- --dbms_output.put_line(p_BILL_NUM);
- END;
- END IF;
- p_QUERY_SQL := 'SQL4WHERE: ' || v_sql_WHERE;
- --dbms_output.put_line(v_sql || v_sql_WHERE || p_BILL_NUM);
- --OPEN mycur(v_WHERE);
- OPEN mycur FOR v_sql || v_sql_WHERE;
- LOOP--循環冊記錄
- fetch mycur INTO V_VOLUME_ID,v_temp1,v_tempBILLCODES ;
- EXIT WHEN mycur%NOTFOUND;
- V_CNT := V_CNT + 1 ;
- --DBMS_OUTPUT.PUT_LINE( V_CNT || ':BILLCODES = ' || v_tempBILLCODES);
- OPEN mycur_split(v_tempBILLCODES,',');
- LOOP--循環生成每一個冊的單據記錄
- fetch mycur_split INTO v_temp2 ;
- EXIT WHEN mycur_split%NOTFOUND;
- --DBMS_OUTPUT.PUT_LINE(' ' || v_temp2);
- --DBMS_OUTPUT.PUT_LINE(' p_BILL_NUM= ' || p_BILL_NUM||',v_temp2='||v_temp2);
- IF (p_BILL_NUM IS NULL OR p_BILL_NUM = TO_NUMBER(v_temp2)) THEN
- v_temp1 := 'INSERT INTO TEMP_VOLUMES_QUERY (SELECT '''|| v_temp2 || ''',A.* FROM PUB_VOLUMES A WHERE volumeid = ' || V_VOLUME_ID || ')';--寫入到臨時表
- --dbms_output.put_line( 'v_temp1=' || v_temp1);
- execute immediate v_temp1;
- END IF;
- END LOOP;
- CLOSE mycur_split;
- END LOOP;
- CLOSE mycur;
- --開始輸出結果
- v_sql := 'SELECT CE.DCODE,CE.VOLUMEID,CE.CORPCODE,CE.CORPNAME,QU.AREANAME,CE.YEAR,CE.MONTH,CE.BILLCODES,CE.VOUCHTYPE,SHI.ROOMNAME, ';
- v_sql := v_sql || 'CE.VOLUMENUM,GUI.CABINETNUM,CE.CABINETLAYER FROM TEMP_VOLUMES_QUERY CE ';
- v_sql := v_sql || 'LEFT OUTER JOIN PUB_CORPS NAME ON CE.CORPCODE = NAME.CORPCODE ';--冊所屬公司(產生單據的公司)
- v_sql := v_sql || 'LEFT OUTER JOIN PUB_AREAS QU ON NAME.AREACODE=QU.AREACODE ';--冊所屬區域(產生單據的公司所在區域)
- v_sql := v_sql || 'LEFT OUTER JOIN PUB_CABINETS GUI ON CE.CABINETCODE=GUI.CABINETCODE ';--冊所在檔案櫃(保存的位置)
- v_sql := v_sql || 'LEFT OUTER JOIN PUB_ARCHIVESROOMS SHI ON GUI.ROOMCODE = SHI.ROOMID ';--冊(櫃)所在檔案室(保存的位置)
- v_sql := v_sql || 'WHERE (GUI.ISMAIL = 0 OR GUI.ISSIGN = 1) ';--尚未郵寄的或者已簽收的
- v_sql := v_sql || 'AND CE.ISBORROW = ''0'' ';--尚未借出去的
- IF (p_AREA_CODES IS NOT NULL AND LENGTH(p_AREA_CODES) >0) THEN --如果需要限制冊的所屬區域
- BEGIN
- v_sql := v_sql || 'AND QU.AREACODE IN ('|| p_AREA_CODES || ') ';
- END;
- END IF;
- p_QUERY_SQL := p_QUERY_SQL || ' SQL4RESULT: ' || v_sql;--返回
- OPEN p_OutCursor FOR v_sql;
- SELECT COUNT(1) INTO V_CNT FROM TEMP_VOLUMES_QUERY;
- dbms_output.put_line(v_sql || ',V_CNT=' || V_CNT);
- dbms_output.put_line(V_CNT);
- delete from TEMP_VOLUMES_QUERY;
- COMMIT;
- end SPLIT_VOLUMES;
- end;
- /
三、結論
1、ON COMMIT DELETE ROWS 說明臨時表是事務指定,每次提交後ORACLE將截斷表(刪除全部行)
2、ON COMMIT PRESERVE ROWS 說明臨時表是會話指定,當中斷會話時ORACLE將截斷表。
3、臨時表(無論會話級還是事務級)中的數據都是會話隔離的,不同session之間不會共享數據。
4、在存儲中使用事務級臨時表時,注意commit前刪除掉本事務的數據,否則可能會出現數據不斷增加的情況(原因尚未搞明白)。
5、 兩種臨時表的語法:
create global temporary table 臨時表名 on commit preserve|delete rows;
用preserve時就是SESSION級的臨時表,
用delete就是TRANSACTION級的臨時表。
6、特性和性能(與普通表和視圖的比較)
臨時表只在當前連接內有效;
臨時表不建立索引,所以如果數據量比較大或進行多次查詢時,不推薦使用;
數據處理比較複雜的時候時錶快,反之視圖快點;
在僅僅查詢數據的時候建議用遊標: open cursor for 'sql clause';