通过DB Link读取视图CLOB字段时遇ORA-01446错误求助
问题:通过DB Link调用函数读取视图CLOB字段触发ORA-01446错误
我们借鉴了fn_dblink_clob函数,原本用来通过DB Link读取物理表的CLOB字段运行正常。现在要把它指向视图,单独执行函数内的动态SQL能正常返回CLOB,但在SQL语句中调用该函数时触发ORA-01446错误,提示无法从含DISTINCT、GROUP BY等的视图中选择ROWID。但远程视图定义里没有JOIN、GROUP BY或DISTINCT子句,单独执行函数构建的动态SQL也能正常运行,求解决方法。
相关代码
函数定义
create or replace function fn_dblink_clob( p_dblink in varchar2 , v_remote_table in varchar2 , p_clob_col in varchar2 , p_rid in urowid ) return clob is /** A function to fetch a CLOB column over a dblink **/ /** Laurence Prescott 25-Aug-17 **/ /** select dblink_clob('some_dblink', 'some_clob_column', rowid) from some_table@some_dblink; Note: Does not work on tables that have a virtual column (eg. xmltype). **/ c_chunk_size constant pls_integer := 4000; v_chunk varchar2(5000); v_clob clob; v_pos pls_integer := 1; begin dbms_lob.createtemporary(v_clob, true, dbms_lob.call); loop execute immediate 'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where rowid = :rid ' into v_chunk using p_rid; begin dbms_lob.append(v_clob, v_chunk); exception when others then if sqlcode = -6502 then exit; else raise; end if; end; if length(v_chunk) < c_chunk_size then exit; end if; v_pos := v_pos + c_chunk_size; end loop; return v_clob; end fn_dblink_clob;
调用函数的SQL语句
select ROW_ID, CASE_ID, fn_dblink_clob('ARGUS_TRANSCT_DB', 'ARGUS_CUSTOM.dlp_case_narrative_rowid','NARRATIVE', NARR.ROW_ID) as NARRATIVE from ARGUS_CUSTOM.dlp_case_narrative_rowid@ARGUS_TRANSCT_DB NARR
错误信息
ORA-01446: cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc. ORA-02063: preceding line from ARGUS_TRANSCT_DB ORA-06512: at "PV_COMPLIANCE.FN_DBLINK_CLOB", line 22 01446. 00000 - "cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc." *Cause: *Action:
远程视图定义
CREATE VIEW DLP_CASE_NARRATIVE_ROWID AS SELECT ROWID AS "ROW_ID", "CASE_ID", "ABBREV_NARRATIVE", "DELETED", "NARRATIVE", "ABBREV_NARRATIVE_J", "NARRATIVE_J", "DLP_REVISION_NUMBER", "EFFECTIVE_START_DATE", "EFFECTIVE_END_DATE", "DELETED_FLAG", "ENTERPRISE_ID" FROM DLP_OWNER.DLP_CASE_NARRATIVE
解决方法
方法一:直接查询基表而非视图
既然视图是基于DLP_OWNER.DLP_CASE_NARRATIVE表创建的,可修改函数调用时的v_remote_table参数为基表名,让函数直接操作物理表,避开视图的ROWID限制。需要确保函数有权限访问该基表。
修改后的调用SQL:
select ROW_ID, CASE_ID, fn_dblink_clob('ARGUS_TRANSCT_DB', 'DLP_OWNER.DLP_CASE_NARRATIVE','NARRATIVE', NARR.ROW_ID) as NARRATIVE from ARGUS_CUSTOM.dlp_case_narrative_rowid@ARGUS_TRANSCT_DB NARR
方法二:改用主键替代ROWID定位记录
如果基表有主键(比如CASE_ID搭配其他唯一字段),可修改函数参数为主键字段,函数内的动态SQL用主键条件过滤,彻底规避ROWID相关问题。
示例修改后的函数:
create or replace function fn_dblink_clob( p_dblink in varchar2 , v_remote_table in varchar2 , p_clob_col in varchar2 , p_case_id in number -- 假设CASE_ID是主键字段 ) return clob is c_chunk_size constant pls_integer := 4000; v_chunk varchar2(5000); v_clob clob; v_pos pls_integer := 1; begin dbms_lob.createtemporary(v_clob, true, dbms_lob.call); loop execute immediate 'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where CASE_ID = :id ' into v_chunk using p_case_id; begin dbms_lob.append(v_clob, v_chunk); exception when others then if sqlcode = -6502 then exit; else raise; end if; end; if length(v_chunk) < c_chunk_size then exit; end if; v_pos := v_pos + c_chunk_size; end loop; return v_clob; end fn_dblink_clob;
对应的调用SQL:
select ROW_ID, CASE_ID, fn_dblink_clob('ARGUS_TRANSCT_DB', 'ARGUS_CUSTOM.dlp_case_narrative_rowid','NARRATIVE', NARR.CASE_ID) as NARRATIVE from ARGUS_CUSTOM.dlp_case_narrative_rowid@ARGUS_TRANSCT_DB NARR
方法三:调整远程视图属性(不推荐)
尝试给视图添加WITH CHECK OPTION或确保视图为可更新状态,但这种方式不一定能解决跨DB Link场景下的ROWID限制问题,因为Oracle对远程视图的ROWID处理存在特殊约束,可靠性较低。
内容的提问来源于stack exchange,提问作者smackenzie
相关产品推荐
相关产品推荐

