【问题标题】:ORA-01461 (with > 4k varchar2) error Only in merge statement. Insert or update works fineORA-01461 (with > 4k varchar2) error 仅在合并语句中。插入或更新工作正常
【发布时间】:2016-07-19 16:23:33
【问题描述】:

这是我的线索... 我在oracle 11g上。搜索了很多,但没有找到。

我需要执行 DML 操作,其中可以包含 > 4k 个字符的数据。

如果我直接在 oracle 中使用 sql 块,就像下一个一样,一切正常

declare 
  txtV varchar2(32000);
BEGIN 
  txtV:= 'MORE THAN 4k CHARS, here only few for readability' ; 
  Update FD_FILTERDEF 
     set SQLFILTER = txtV 
   where id='blabla';  
END;

但是!!! 如果我使用合并语句,它会给我错误ORA-01461

declare 
  txtV varchar2(32000);
BEGIN 
  txtV:= '' ; 
  MERGE INTO FD_FILTERDEF A 
        USING ( select  txtV C0 
                  from dual) ST 
           ON (A.CODE = 'bla bla') 
  WHEN MATCHED THEN 
    Update set A.SQLFILTER = st.C0  
  WHEN NOT MATCHED THEN 
    insert (CODE  ,SQLFILTER ) 
      values ('bla bla'  , ST.C0  );  
END; 

如果有一些提示将不胜感激:)

【问题讨论】:

  • 请出示您的表格定义
  • fd_filterdef.sqlfilter 的类型是什么? clob 可能吗?
  • FD_FILTERDEF.SQLFILTER 是一个 CLOB 列

标签: oracle plsql oracle11g merge ora-01461


【解决方案1】:

使用这个:

create table fd_filterdef
( code varchar2(10) primary key
, sqlfilter clob );

declare
    txtv varchar2(32000);
begin
    txtv := rpad('select statement, really really long', 5000, ' etc');

    merge into fd_filterdef a
    using (select 'bla bla' as code from dual) st
    on (a.code = st.code)
    when matched then
        update set a.sqlfilter = txtv
    when not matched then
        insert (code, sqlfilter)
        values (st.code,txtv);
end;
/

select code, length(sqlfilter) from fd_filterdef;

CODE       LENGTH(SQLFILTER)
---------- -----------------
bla bla                 5000

从 dual 中选择 long 变量会隐式将其转换为 SQL varchar2,在 12c 之前只能容纳 4000 个字节。

【讨论】:

    【解决方案2】:

    你不能选择 varchar2 超过 4k https://docs.oracle.com/cd/B28359_01/server.111/b28320/limits001.htm

    查看你的代码

     select  txtV C0 from dual
    

    但是在 oracle 12c 中你可以 https://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#SQLRF30020

    【讨论】:

    • 这不完全正确...如果我使用variable='text of more than 4k chars'; 然后select variable from dual 我没有问题,所以选择大于4k 的变量显然是允许的。问题不在于 select 语句,而在于 merge one。
    • @Sabbe,如果我尝试select v1 into v2 from dual v1 > 4k,我会得到ORA-01460: unimplemented or unreasonable conversion requested(至少在 11g 中)。
    • @William Robertson 是的,当然因为它是 varchar2,而不是 clob 或其他
    • 确实如此 - 所以一种解决方案是将 textv 更改为 clob。但是,我们根本不通过 SQL 查询传递值,从而避免了复杂性。
    【解决方案3】:

    @William 很好的提示,这是你发布的作品。

    但我很确定我已经测试了一个非常相似的语法,其中唯一的区别在于 select 语句, 您提供的工作正常...以下会引发错误:

    declare 
      txtV varchar2(32000);
    BEGIN 
      txtV:= '5000 chars ....';
      MERGE INTO FD_FILTERDEF A 
            USING ( select  'not used' Code from dual) ST 
               ON (A.CODE = 'TESTCODE') 
      WHEN MATCHED THEN 
        Update set A.SQLFILTER = txtV   --<<<< LOOK HERE I USE DIRECTLY THE VARIABLE DELCARED, NOT THE ONE FROM SELECT STMT 
      WHEN NOT MATCHED THEN 
        insert (CODE  ,SQLFILTER ) 
          values (st.code  , txtV  );  
    END;
    

    【讨论】:

    • 你得到什么错误?我只得到一个 PK 违规,因为更改连接条件使其尝试添加具有相同代码的新行。
    • PK违例!? ... 为什么?合并永远不应该给出 PK 违规错误(如果在“ON”条件下使用真正的 pk。无论如何,我使用我的第一个(不工作)版本得到的错误是 ORA-01461: can bind a LONG value only for insert into a LONG column
    • 上面的代码示例给出了 PK 冲突,因为 a.code 与文字 TESTCODE 不匹配,因此使用了 when not matched then insert 子句。两次执行将尝试插入同一行,在我的示例中,我在 code 上定义了一个 PK。我不确定它是为了演示什么。
    • @William 是的,你是对的。我错误地认为,使用直接键值,而不是从“using....”语句的内部“select ...”中获取它,会以相同的方式工作。 :) 无论如何,再次感谢您解决我问题的提示。
    【解决方案4】:

    @William ...好吧,也许我在写脚本时有点混乱。我对“pk 错误”的原因感到惊讶,因为我的脚本如下所示。我打算完全不使用“选择”语句,只是在插入和更新中传递代码(如下),因为我以编程方式构建查询并用占位符替换值...... 这样一来,就完全没有pk错误了。当然,在您的示例中,原因在插入中使用了查询中的代码,但在更新中使用了值“TESTCODE”......所以它正在搜索(和更新)代码,但插入另一个:P 对不起我的错误:)

    declare 
      txtV varchar2(32000);
    BEGIN 
      txtV:= '5000 chars ....';
      MERGE INTO FD_FILTERDEF A 
            USING ( select  'not used' Code from dual) ST 
               ON (A.CODE = 'TESTCODE') 
      WHEN MATCHED THEN 
        Update set A.SQLFILTER = txtV   --<<<< LOOK HERE I USE DIRECTLY THE VARIABLE DELCARED, NOT THE ONE FROM SELECT STMT 
      WHEN NOT MATCHED THEN 
        insert (CODE  ,SQLFILTER ) 
          values ('TESTCODE'  , txtV  );  
    END;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 2022-12-21
      相关资源
      最近更新 更多