【问题标题】:Pass reference type across a DB Link跨数据库链接传递引用类型
【发布时间】:2014-05-21 08:26:46
【问题描述】:

我试图通过 DB 链接传递引用类型,但收到错误消息,告诉我它在过程中对 DB 链接的引用是非法的。我已经在包的正文和规格中指定了它,但在搜索解决方案后不确定如何解决它。我正在使用 oracle 10g 作为 11g oracle DB 的引用类型。

版本: Oracle 数据库 11g 企业版 11.2.0.3.0 版

Oracle 数据库 10g 企业版 10.2.0.5.0 版

[Error] PLS-00331 (13: 43): PLS-00331: illegal reference to test.DATA_T@TESTDB('PARAMETERS')

这似乎是包装规范中的一个问题:

   PROCEDURE SendCollection(o_data IN OUT data_t@TESTDB,
                   o_seq  IN OUT seq_t@TESTDB,
                   i_flag IN     CHAR);

我认为以上是正确的,欢迎任何指点和建议

【问题讨论】:

  • 上次我看了,我不相信这是可能的。如果可能的话,它很可能是高度依赖于版本的,所以你真的想指定你正在使用的 Oracle 的精确版本。
  • 我也不认为这是可能的,因为您的本地实例无法知道远程类型是否被修改或删除;它需要能够使您的过程无效,然后在使用时重新编译它。 It isn't specifically listed as a restriction though.
  • 按推荐添加,oracle 版本:oracle (10g) 是传递引用类型的地方,oracle (11g) 也是传递它的地方
  • 你 100% 确定这是不可能的吗?奇怪的是它也没有在那里列出
  • 不,不是 100%,但我不认为它可以做到,错误表明它是不允许的。但是错误似乎并不指向声明;传递'PARAMETERS' 的代码是什么,远程数据库上的类型是如何定义的?也许一个小的测试用例会有所帮助。

标签: sql database oracle plsql


【解决方案1】:

线程仍然是开放的,所以我会回答以后可能需要帮助的人。 如果你想传递一个对象,那么Oracle根据Oracle docs: Restriction on Using User-Defined Types with a Remote Database禁止这样做:

对象或用户定义的类型(特别是使用 SQL CREATE TYPE 语句声明的类型,与在 PL/SQL 包中声明的类型相反)目前仅在单个数据库中有用。

但是,您可以通过 DB 链接发送 recordtable 类型,但您必须:

  1. 要么为它们分配一个 OID,然后在两个数据库上使用 相同 OID 创建它们:

    -- Obtain an OID
    SELECT SYS_OP_GUID() FROM DUAL;
    
    -- Result
    SYS_OP_GUID()
    ----------------
    D38A360CF86C41618DC2C40B551214C3
    
    -- Create your type
    create or replace type MY_TAB oid 'E8892B5D76E7419A951AEBA63A7AB3BF' as table of varchar2(50);
    
  2. 或者将它们放在远程数据库上的一个包中:

    -- Create a DB link API package
    create or replace package DBLINK_API as
      type MY_TAB is table of varchar2(50);
    end DBLINK_API;
    
    -- And a function that uses that type
    create or replace function getCount(myPar DBLINK_API.MY_TAB) return number is
    begin
      return myPar.count;
    end getCount;
    

之后,您可以从数据库中使用它。首先让我们用数据创建一些测试表。

create table TEST_TABLE
(
  ID varchar2(50) not null
);

insert into TEST_TABLE values('Value 1');
insert into TEST_TABLE values('Value 2');
insert into TEST_TABLE values('Value 3');
insert into TEST_TABLE values('Value 4');
insert into TEST_TABLE values('Value 5');

然后最后使用本地表向远程函数发送一个ID表,这对我们计数非常有用:

declare
  vals DBLINK_API.MY_TAB@MY_DBLINK;
begin
  select ID bulk collect
  into   vals
  from   TEST_TABLE;

  DBMS_OUTPUT.put_line(getCount@MY_DBLINK(vals));
end;

在这个例子中看起来有点过头了,你可能更喜欢在远程过程中使用指向数据库的 DB 链接从 TEST_TABLE 中进行选择。我不确定性能会如何受到影响,也许这种方法对于较大的表或慢速选择会更好,但它会产生相同的结果。

【讨论】:

    【解决方案2】:

    不允许引用远程类型。文档暗示这是不可能的,但不是 100% 清楚这一点。

    (使用社区 wiki,因为此答案是 cmets 的摘要。)

    更新:远程数据库对象引用(有效)

    Oracle 的一些文档很糟糕。有时必须尝试一下才能真正确定。一个可行的解决方案:

    DECLARE
    
       v_rec_sample sample_table@remotedb%ROWTYPE;
    
    BEGIN
    
       select *
         into v_rec_sample
         from doj_crime@remotedb
        where rownum = 1;
    
       dbms_output.put_line(v_rec_sample.crime_detail);
       dbms_output.put_line(v_rec_sample.location);
    
    END;
    

    它有效。可以使用 dblink 和远程定义的对象在本地声明的变量和集合上创建数据类型定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 2012-03-23
      相关资源
      最近更新 更多