[英]bulk collect dynamic sql
我必須編寫一個動態sql游標,其中有幾種可能會生成選擇查詢的可能性。 因此,我選擇動態方式,並且使用DBMS_SQL包動態創建游標並動態獲取數據。
但是,結果集將是巨大的。 大約11GB(有240萬條記錄,假設每列大約50Byte varchar,select語句的長度約為80列)
因此,我無法立即打開游標。 我想知道是否有一個功能,其中我可以從curosr中獲取數據,同時保持curosr處於打開狀態,例如說有1000條記錄的塊(我將不得不動態地執行此操作)
請找到附帶的代碼,該代碼僅可獲取並打印列的值(一個示例案例),我想在這里使用bul collect \\
謝謝
---------------code sample--------------------------------------
--create or replace type TY_DIMDEAL AS TABLE OF VARCHAR2(50) ;
create or replace procedure TEST_PROC (po_recordset out sys_refcursor)
as
v_col_cnt INTEGER;
v_ind NUMBER;
rec_tab DBMS_SQL.desc_tab;
v_cursor NUMBER;
lvar_output number:=0;
lvar_output1 varchar2(100);
lvar_output3 varchar2(100);
lvar_output2 varchar2(100);
LVAR_TY_DIMDEAL TY_DIMDEAL;
lvarcol varchar2(100);
begin
--
LVAR_TY_DIMDEAL := TY_DIMDEAL();
lvar_output1 := '';
v_cursor := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor, 'select to_char(Field1) , to_char(fiel2) , to_char(field3) from table,table2 ', dbms_sql.native);
dbms_sql.describe_columns(v_cursor, v_col_cnt, rec_tab);
FOR v_pos in 1..rec_tab.LAST LOOP
LVAR_TY_DIMDEAL.EXTEND();
DBMS_SQL.define_column( v_cursor, v_pos ,LVAR_TY_DIMDEAL(v_pos),20);
END LOOP;
-- DBMS_SQL.define_column( v_cursor, 1 ,lvar_output1,20);
--DBMS_SQL.define_column( v_cursor, 2 ,lvar_output2,20);
--DBMS_SQL.define_column( v_cursor, 3 ,lvar_output3,20);
v_ind := dbms_sql.execute( v_cursor );
LOOP
v_ind := DBMS_SQL.FETCH_ROWS( v_cursor );
EXIT WHEN v_ind = 0;
lvar_output := lvar_output+1;
dbms_output.put_line ('row number '||lvar_output) ;
FOR v_col_seq IN 1 .. rec_tab.COUNT LOOP
LVAR_TY_DIMDEAL(v_col_seq):= '';
DBMS_SQL.COLUMN_VALUE( v_cursor, v_col_seq,LVAR_TY_DIMDEAL(v_col_seq));
dbms_output.put_line (LVAR_TY_DIMDEAL(v_col_seq));
END LOOP;
END LOOP;
end TEST_PROC;
PL / SQL最佳實踐之一是從游標中以合理大小的塊獲取數據,同時保持游標處於打開狀態。
上面的文檔(請參閱Code 38
項 )勾畫出一種在運行時才知道選擇列表的方法。 基本上:
定義適當的類型以將結果提取到其中。 假設所有返回的列的類型均為VARCHAR2
:
-- inside DECLARE Ty_FetchResults IS TABLE OF DBMS_SQL.VARCHAR2_TABLE; lvar_results Ty_FetchResults;
在每次調用DBMS_SQL.FETCH_ROWS
之前, DBMS_SQL.FETCH_ROWS
調用DBMS_SQL.DEFINE_ARRAY
以啟用批量提取。
DBMS_SQL.FETCH_ROWS
以從游標中獲取1000行。 DBMS_SQL.COLUMN_VALUE
將獲取的數據復制到結果數組中。 FOR
循環中FOR
記錄地處理結果。 不必擔心獲取的記錄數:如果有要處理的記錄,則FOR
循環將正確運行; 如果結果數組為空,則FOR
循環將不會運行。 DBMS_SQL.CLOSE
。 DBMS_SQL.CLOSE
游標。 您的循環主體應如下所示:
LOOP
FOR j IN 1..v_col_cnt LOOP
DBMS_SQL.DEFINE_ARRAY(v_cursor, j, lvar_results(j), 1000, 1);
END LOOP;
v_ind := DBMS_SQL.FETCH_ROWS(v_cursor);
FOR j IN 1..v_col_cnt LOOP
lvar_results(j).DELETE;
DBMS_SQL.COLUMN_VALUE(v_cursor, j, lvar_results(j));
END LOOP;
-- process the results, record by record
FOR i IN 1..lvar_results(1).COUNT LOOP
-- process a single record...
-- your logic goes here
END LOOP;
EXIT WHEN lvar_results(1).COUNT < 1000;
END LOOP;
-- don't forget: DBMS_CLOSE(v_cursor);
另請參見從PL / SQL執行SQL:最佳和最差實踐 。
限制條款可以解決!
PL / SQL集合本質上是內存中的數組,因此龐大的集合可能會由於其所需的內存量而對系統性能產生不利影響。 在某些情況下,可能有必要將正在處理的數據拆分為多個塊,以使代碼對內存更友好。 可以使用BULK COLLECT語法的LIMIT子句來實現這種“分塊”。
批量收集后,您可以使用限制條款來限制您的RS。 超出限制后,您可以抓住剩余的行。 請參閱此文章http://www.dba-oracle.com/plsql/t_plsql_limit_clause.htm
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.