Oracle && OceanBase 相关文档,希望互相学习,
共同进步
1.背景
今天需要将远端的一张表中的clob字段,插入本地的表字段中。发现单表插入可以,但是再带一个本库表的限制条件,就会报下面的错误:
(clob+dblink "ORA-22992:无法使用从远程表选择的 LOB定位符")

2. 实验
2.1 表准备
1)本地:表ANNEX_TMP、dblink
表 ANNEX_TMP :其中 attachments字段为clob,准备存放远端@xxx 表的clob字段。
表 TBL_EXTRACT_BANK_ALL :存放 bank_code 字段的范围
sql
create table ANNEX_TMP
(
kid VARCHAR2(32) not null,
attachments CLOB,
bank_code VARCHAR2(32) not null
);
2)远端:表 ZCS_DIS@xxx
表 ZCS_DIS@xxx:其中 pro_atta_down 字段为clob,存放的逗号分隔的 xxids 字符串。
sql
select t.kid,t.pro_atta_down,t.bank_code,to_char(pro_atta_down) bb
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'

2.2 查询
本地查询:带exists 条件 和不带它 都 ok
sql
--带条件查询 ok
select t.kid,t.pro_atta_down,t.bank_code,to_char(pro_atta_down) bb
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'
and EXISTS (SELECT 1 FROM TBL_EXTRACT_BANK_ALL P
WHERE P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE);
截图: 可以出结果 ok

2.3 插入
1)插入本地表 ORA-22992
在查询的基础上,加上插入:
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code--,to_char(pro_atta_down) bb
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'
and EXISTS (SELECT 1 FROM TBL_EXTRACT_BANK_ALL P
WHERE P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE);
结果: 报错 ORA-22992 无法使用从远程表选择的 LOB定位符

2)插入本地表 去掉exists, 插入ok
在插入的基础上,去掉 and exists 条件,再次插入
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code--,to_char(pro_atta_down) bb
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'
/*and EXISTS (SELECT 1 FROM TBL_EXTRACT_BANK_ALL P
WHERE P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE)*/;
结果: 插入ok

3)插入本地表 加上 exists 条件 + 去掉clob条件,插入 ok
在插入的基础上,加上 exists 条件 + 去掉clob条件,再次插入 ok
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code--,to_char(pro_atta_down) bb
from zcs_dis@zcs t
where /*t.pro_atta_down is not null
and*/ kid='1803966222369718273'
and EXISTS (SELECT 1 FROM TBL_EXTRACT_BANK_ALL P
WHERE P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE);
结果:ok

问题出现:远端clob字段是可以插入本地clob字段中的,可以带clob字段的条件,但是不能跨库。改为and exists 为远端的限制条件,再次测试:
4)插入本地表 加上 远端exists 条件 + clob条件,插入 ok
在插入的基础上,加上 远端exists 条件 + clob条件,再次插入 ok
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'
and EXISTS (SELECT 1 FROM ZCS_DIS@ZCS P
WHERE P.BANK_CODE = t.BANK_CODE)
结果:ok

同一个dblink的远端限制条件,才被认为是同样的远端。用户.表 这种格式也会被认为是分布式查询。分布式查询的where 子句+ 直接传递 lob定位器 不支持。
5)插入本地表 加上 远端另一个库的exists 条件 + clob条件,报错
在插入的基础上,加上 远端另一个库的exists 条件 + clob条件,再次插入 报错
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code
from zcs_dis@zcs t
where t.pro_atta_down is not null
and kid='1803966222369718273'
and EXISTS (SELECT 1 FROM sys_bank@basic P
WHERE P.BANK_CODE = t.BANK_CODE)
结果:插入报错,但是单独查询是可以的,只是插入报错


6)插入本地表 任何dblink + 去掉clob字段条件 ok
sql
insert into ANNEX_TMP
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code
from zcs_dis@zcs t
where /*t.pro_atta_down is not null
and*/ kid='1803966222369718273'
and EXISTS (SELECT 1 FROM sys_bank@basic P
WHERE P.BANK_CODE = t.BANK_CODE)
结果: 可以加任何条件,但是不能和clob字段的条件同时存在

2.4 验证结果
通过2.3实验,发现是clob字段条件 不能 和分布式表条件一起用来插入,否则会报错。为了验证,下面改为两个分布式表直接连接,再次验证上面的结果。
1)直接连接 验证问题
sql
select t.kid,t.pro_atta_down,t.bank_code
from zcs_dis@zcs t,TBL_EXTRACT_BANK_ALL P
where /*t.pro_atta_down is not null
and*/ t.kid='1803966222369718273'
AND P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE
结果: 放开clob条件会报错,注释掉后 正常查询。

网上找资料,显示可能是由于 DBLink 对 LOB 的支持限制 。Oracle 在某些版本中,不支持在分布式查询的 WHERE 子句包含复杂逻辑时直接传递 LOB 定位器。
2)处理解决
解决:创建本地临时表,在本地进行关联过滤和最终插入。将"跨库 LOB 传输"和"本地逻辑判断"分离开,避免了 Oracle 分布式引擎在处理 LOB 时的类型检查冲突*。*
sql
--1清空
truncate table ANNEX_TMP;
--2创建临时表1
create table ANNEX_TMP1 as select * from ANNEX_TMP;
sql
--3插入临时表1
insert into ANNEX_TMP1
(kid, attachments, bank_code)
select t.kid,t.pro_atta_down,t.bank_code
from zcs_dis@zcs t,TBL_EXTRACT_BANK_ALL@tbl P
where /*t.pro_atta_down is not null
and*/ t.kid='1803966222369718273'
AND P.END_DT = DATE '3000-12-31'
AND P.BANK_CODE = t.BANK_CODE
;
commit;
--4插入表
insert into ANNEX_TMP
(kid, attachments, bank_code)
select * from ANNEX_TMP1;
commit;
sql
--查询表
select t.*,to_char(t.attachments) aa,
DBMS_LOB.SUBSTR(t.attachments,4000,1) bb
from ANNEX_TMP t;
结果:ok 解决

3.实验总结
总结:解决 clob+dblink 怪异插入 "ORA-22992:无法使用从远程表选择的 LOB定位符"。可以使用创建本地临时表,在本地进行关联过滤和最终插入。将"跨库 LOB 传输"和"本地逻辑判断"分离开,避免了 Oracle 分布式引擎在处理 LOB 时的类型检查冲突*。*
采用"先落地,后处理"策略 :由于涉及 DBLink 和 CLOB,直接带复杂
WHERE条件的插入容易触发内部类型错误。先将远端数据INSERT到本地一个临时表中(这一步通常成功),然后在本地表之间进行INSERT ... SELECT ... WHERE EXISTS操作。这是处理跨库大字段最稳定、性能也可控的方法。
实验验证:ok 
Oracle其他文档,希望互相学习,
共同进步
【Oracle专栏】跨服务器调用ORA-02064: 不支持分布式操作
【Oracle专栏】ORA-02069: global_names 参数
【Linux && Oracle】Linux调用oracle 返回值
Oracle-找回误删的表数据(LogMiner 挖掘日志)_oracle日志挖掘恢复数据-CSDN博客
oracle 跟踪文件--审计日志_oracle审计日志-CSDN博客
欢迎各位同行点赞、评论、收藏,共同探讨!💪