最近做了一个非常奇葩的事情“通过DBLINK远程查询带DBLINK的视图”:

有A、B两个数据库实例,A下面有user1和user2两个用户,B实例下有用户user3。

现在user1 用户下建连接user3名为link3的DBLINK,并写视图user1.v_test查询 user3 用户下的tableA。

CREATE OR REPLACE VIEW user1.v_test AS
select field1,field2 
from tableA@link3
where 1=1;

在user2用户下调用user1.v_test即报“ORA-04054:数据库连接 LINK3 不存在”。意思就是user2不能用user1的私有dblink,因此我们要想办法使user2查询的时候在user1本地执行dblink查询。

解决办法如下:

在user1建函数调用user1.v_test 返回表类型

create or REPLACE type type_tableA is OBJECT (
  field1 VARCHAR2(6),
  field2 VARCHAR2(200)
  );

create or REPLACE type tb_tableA is table of type_tableA;


function f_tb_tableA()
return tb_tableA 
is
o_tb tb_tableA := tb_tableA();
i number := 0;
begin
  for v_rec in (select t.field1,t.field2
  from user1.v_test t
  WHERE 1=1) loop
    o_tb.extend;
    i := i + 1;
    o_tb(i) := type_tableA (
     v_rec.field1,
     v_rec.field2);
  end loop;
  return o_tb;
end;

还可参考:在Oracle的函数中,返回表类型

调用方式如下:

select * from table(user1.f_tb_tableA());

但是,当有另外一个用户user4 通过dblink(名为link2) 访问user2调用f_tb_tableA(),即在user4下执行:select * from table(user1.f_tb_tableA@link2());

报错“ORA-30626:不支持远程对象类型的功能/过程参数”。意思就是通过DBLINK不能调用返回值为类型的功能或过程。

因此我们继续想办法,既然返回值为“类型”的无法通过dblink, 那就想办法用可以通过dblink 的方法。我想到写个视图封装以上的查询语句,将视图给user4查询。

CREATE OR REPLACE VIEW user1.v_test_trans AS
select field1,field2 
from table(user1.f_tb_tableA())
where 1=1;

然后在user4用户下查询user1.v_test的方法如下:

select field1,field2 
from user1.v_test_trans@link2
where 1=1;

至此问题解决。

当然实际工程中我还使视图带参数,通过包体实现带参查询。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐