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

Oracle 使用数据库链接从all_view.text中提取长列值

ASKTOM 2019-05-21
1202

问题描述

嗨,

我必须使用DBLink将ALL_VIEWS的数据从一个数据库传输到另一个数据库。两者都是Oracle数据库,版本也相同,即Oracle 18c。很少有视图的文本列长度超过32767,不能使用本机动态sql传输。因此,我使用DBMS_SQL来实现同样的目标。

我正在尝试使用DBMS_SQL.COLUMN_VALUE_LONG从ALL_VIEW @ 中提取长列值,并在CLOB列中插入结果。下面是我正在使用的PLSQL块。(请用工作中的DB链接替换db_link)

CREATE TABLE san_ora03101_test
( resource_name VARCHAR2 (100),
  view_owner    VARCHAR2(100),
  view_name   VARCHAR2(100),
  text      CLOB
);
/

DECLARE

    s_sql      CLOB:= q'[SELECT *
                          FROM (
                                SELECT v.view_name resource_name
                                     , v.owner        view_owner
                                     , v.view_name
                                     , v.text text
                                  FROM all_views@REPORTING_SYSTEM v)]'; 
    cur        BINARY_INTEGER;
    s_res_name VARCHAR2(100);
    s_owner    VARCHAR2(100);
    s_vname    VARCHAR2(100);
    c_text     CLOB;
    n_res      NUMBER;
BEGIN      

        cur:=DBMS_SQL.OPEN_CURSOR;
        DBMS_SQL.PARSE(cur, s_sql, DBMS_SQL.NATIVE);
        DBMS_SQL.DEFINE_COLUMN(cur, 1, s_res_name, 100);
        DBMS_SQL.DEFINE_COLUMN(cur, 2, s_owner, 100);
        DBMS_SQL.DEFINE_COLUMN(cur, 3, s_vname, 100);
        DBMS_SQL.DEFINE_COLUMN_LONG(cur, 4);

        n_res:=DBMS_SQL.EXECUTE(cur);
        WHILE DBMS_SQL.FETCH_ROWS(cur) > 0 LOOP
            DBMS_SQL.COLUMN_VALUE(cur, 1, s_res_name);
            DBMS_SQL.COLUMN_VALUE(cur, 2, s_owner);
            DBMS_SQL.COLUMN_VALUE(cur, 3, s_vname);
            DECLARE
                c_tmp   CLOB;
                n_pos   INTEGER:=0;
                s_tmp   VARCHAR2(32767);
                n_tpos  INTEGER;
                n_piece_len NUMBER:= 32767;
            BEGIN
                LOOP
                    dbms_output.put_line(' n_pos: '||n_pos||',s_tmp: '||s_tmp||',n_tpos: '||n_tpos||',cur: '||cur||', s_res_name: '||s_res_name||',s_owner: '||s_owner||',s_vname: '||s_vname);
                    
          DBMS_SQL.COLUMN_VALUE_LONG(cur, 4, n_piece_len, n_pos, s_tmp, n_tpos);
                        
                    c_tmp:=c_tmp||s_tmp;
                    n_pos:=n_pos+n_piece_len;
                    EXIT WHEN n_tpos < n_piece_len;
                END LOOP;
                c_text:=c_tmp;
                
            EXCEPTION
                WHEN OTHERS THEN
                  dbms_output.put_line(' ERR_STACK: '||dbms_utility.format_error_stack||', SQL_TRACE: '||dbms_utility.format_error_backtrace);
                RAISE;
            END;
            
        -- INSERT RECORDS
        INSERT
          INTO san_ora03101_test
             (
               resource_name
             , view_owner
             , view_name
             , text
             )
        VALUES
             (
               s_res_name
             , s_owner
             , s_vname
             , c_text
             );

        END LOOP;
        DBMS_SQL.CLOSE_CURSOR(cur);
        COMMIT;
EXCEPTION
    WHEN OTHERS THEN
        IF DBMS_SQL.IS_OPEN(cur) THEN
            DBMS_SQL.CLOSE_CURSOR(cur);
        END IF;
        RAISE;
END;
/
复制


尝试使用DBMS_SQL.COLUMN_VALUE_LONG() 获取长列值时,上述块失败,并显示 “ORA-03101: 无效输入数据”。

ORA-03101: invalid ORA-06512: at line 79
ORA-06512: at line 51
ORA-02063: preceding line from REPORTING_SYSTEM
ORA-06512: at "SYS.DBMS_SQL", line 2066
ORA-06512: at line 40


Oracle数据库版本是: Oracle数据库18c企业版版本18.0.0.0.0。但是,此语句在11g环境中可以正常工作。如果我们删除db_link,那么这也可以正常工作。

专家解答

我有一个希望更容易的提议给你。使用SQLPlus中的COPY命令在本地获取数据,然后您可以透明地将 (本地) 长转换为CLOB。

SQL> create table local_all_views
  2  ( owner varchar2(30), view_name varchar2(128), text_length int, text long);

Table created.

SQL>
SQL> set long 1000000
SQL> copy from scott/tiger@remote_db -
>   insert local_all_views (owner, view_name, text_length, text ) -
>   using select owner, view_name, text_length, text from all_views;

Array fetch/bind size is 15. (arraysize is 15)
Will commit when done. (copycommit is 0)
Maximum long size is 1000000. (long is 1000000)
   7249 rows selected from scott@remote_db.
   7249 rows inserted into LOCAL_ALL_VIEWS.
   7249 rows committed into LOCAL_ALL_VIEWS at DEFAULT HOST connection.

SQL>
SQL> alter table local_all_views modify text clob;

Table altered.

SQL> desc local_all_views
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(30)
 VIEW_NAME                                          VARCHAR2(128)
 TEXT_LENGTH                                        NUMBER(38)
 TEXT                                               CLOB
复制


“remote_db” 是一个tnsnamers.ora条目,而不是数据库链接
文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论