暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 将refcursor存储到物理表

askTom 2017-05-08
196

问题描述

将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操作
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论