问题描述
将refcursor存储到物理表中而不影响性能的最佳方法。我确实有一个代码构建,但是当数据很大时,它需要太多时间。同样,此代码似乎不可扩展,因为它会为传递的每个不同游标连续创建临时表。任何即兴发挥这一点的建议都会很好。
create or replace procedure unit_test
(p_cur_data in oUT SYS_REFCURSOR,
p_temp_tab_param in number)
as
lv_cur_pntr NUMBER;
lv_nbr_of_cols NUMBER;
lv_out_col_desc DBMS_SQL.DESC_TAB;
lv_build_gtt_struct CLOB;
lv_sql CLOB;
lv_gtt_tab_nm ALL_TABLES.TABLE_NAME%TYPE := 'ZZ_data'||p_temp_tab_param;
lv_varchar2 VARCHAR2(4000);
lv_number NUMBER;
lv_date DATE;
lv_data CLOB;
begin
lv_cur_pntr := DBMS_SQL.to_cursor_number(p_cur_data);
DBMS_SQL.DESCRIBE_COLUMNS(lv_cur_pntr, lv_nbr_of_cols, lv_out_col_desc);
begin
EXECUTE IMMEDIATE 'DROP TABLE '||lv_gtt_tab_nm;
exception
when others then
null;
end;
--lv_build_gtt_struct := 'CREATE GLOBAL TEMPORARY TABLE '||lv_gtt_tab_nm||'(';
lv_build_gtt_struct := 'CREATE TABLE '||lv_gtt_tab_nm||'(';
for i in lv_out_col_desc.first .. lv_out_col_desc.last
loop
lv_build_gtt_struct := lv_build_gtt_struct ||lv_out_col_desc(i).col_name||' '||
case
when lv_out_col_desc(i).col_type in (2,8) THEN 'NUMBER'
when lv_out_col_desc(i).col_type in (12) THEN 'DATE'
when lv_out_col_desc(i).col_type in (11) THEN 'ROWID'
when lv_out_col_desc(i).col_type in (23) THEN 'RAW'
when lv_out_col_desc(i).col_type in (23) THEN 'LONG RAW'
ELSE 'VARCHAR2(500)' END||',';
end loop;
--lv_build_gtt_struct := rtrim(lv_build_gtt_struct,',')||') ON COMMIT DELETE ROWS';
lv_build_gtt_struct := rtrim(lv_build_gtt_struct,',')||') tablespace abcdefg';
dbms_output.put_line(lv_build_gtt_struct);
EXECUTE IMMEDIATE lv_build_gtt_struct;
FOR i IN 1 .. lv_nbr_of_cols
LOOP
IF lv_out_col_desc(i).col_type IN (2,8) THEN
DBMS_SQL.DEFINE_COLUMN(lv_cur_pntr, i, lv_number);
ELSIF lv_out_col_desc(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(lv_cur_pntr, i, lv_date);
ELSE
DBMS_SQL.DEFINE_COLUMN(lv_cur_pntr, i, lv_varchar2, 4000);
END IF;
END LOOP;
WHILE DBMS_SQL.FETCH_ROWS(lv_cur_pntr) > 0 LOOP
lv_data := NULL;
FOR i IN 1 .. lv_nbr_of_cols
LOOP
IF lv_out_col_desc(i).col_type in (2,8) THEN
DBMS_SQL.COLUMN_VALUE(lv_cur_pntr, i, lv_number);
lv_data := lv_data ||nvl(lv_number,0)||',';
ELSIF lv_out_col_desc(i).col_type = 12 THEN
DBMS_SQL.COLUMN_VALUE(lv_cur_pntr, i, lv_date);
lv_data := lv_data ||''''||nvl(lv_date,'17-DEC-9999')||''',';
ELSE
DBMS_SQL.COLUMN_VALUE(lv_cur_pntr, i, lv_varchar2);
lv_data := lv_data||''''||replace(nvl(lv_varchar2,'INVALIDINVALID'),'''','')||''',';
END IF;
END LOOP;
--dbms_output.put_line('INSERT INTO '||lv_gtt_tab_nm|| ' VALUES ('||rtrim(lv_data,',')||')');
EXECUTE IMMEDIATE 'INSERT INTO '||lv_gtt_tab_nm|| ' VALUES ('||rtrim(lv_data,',')||')';
END LOOP;
DBMS_SQL.CLOSE_CURSOR(lv_cur_pntr);
COMMIT;
end;
专家解答
我不知道你想在这里实现什么。
您的代码似乎:
-拿一个光标
-基于它创建临时表
-将数据存储在该临时表中
我的问题是为什么?
如果您需要保存这些数据一会儿,那么您可以使用闪回查询在那个时间点重复获取数据。如果您需要长时间保存该数据,那么我会认为这对于 * 任意 * SQL语句来说不是很有意义的事情。
无论如何,如果您的要求出于任何原因都是合法的,那么
a) 重新编码plsql解决方案以使用数组提取和数组插入。这里的例子
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:455220177497
b) 而不是传递游标,而是传递原始SQL,并使用它执行cta操作
您的代码似乎:
-拿一个光标
-基于它创建临时表
-将数据存储在该临时表中
我的问题是为什么?
如果您需要保存这些数据一会儿,那么您可以使用闪回查询在那个时间点重复获取数据。如果您需要长时间保存该数据,那么我会认为这对于 * 任意 * SQL语句来说不是很有意义的事情。
无论如何,如果您的要求出于任何原因都是合法的,那么
a) 重新编码plsql解决方案以使用数组提取和数组插入。这里的例子
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:455220177497
b) 而不是传递游标,而是传递原始SQL,并使用它执行cta操作
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




