【问题标题】:Error : ORA-01704: string literal too long. Dynamically assign CLOB to variable错误:ORA-01704:字符串文字太长。将 CLOB 动态分配给变量
【发布时间】:2016-09-17 12:36:13
【问题描述】:

我的问题很重要。

我应该执行运行INSERT INTO 查询的PL/SQL 脚本。它看起来像:

DECLARE
newId NUMBER(38,0) := &1;
BEGIN
Insert into FOO ("ID", "DESCRIPTION")
values (newId+1, 'LARGE CLOB WHICH PRODUCES EXCEPTION');
-- A LOT OF INSERT QUERIES
END;
/
exit;

所以,我发现将 CLOB 分配给 VARCHAR2 变量是个好主意,因为它可能是 32767 字节长。我的目标是为每个INSERT INTO 查询做到这一点。喜欢:

--assign CLOB to VARCHAR2 variable
-- INSERT variable instead of CLOB type

我想指出我在脚本中有很多INSERT INTO 查询,所以我应该在每个INSERT INTO 查询之前重新分配变量,我该怎么做?

【问题讨论】:

  • 我不确定你真正在问什么 - 如何为 varchar2 PL/SQL 变量赋值?你的值都小于 32k 吗?
  • 将超大数据从文件中读取到数据库lob列或plsql lob变量中;或者将文字分成大小小于 32k 的块,使用 sql 更新或使用 dbms_lob 包重新组装这些部分。
  • 您尝试做的一件事似乎是识别太大而无法分配给 varchar2 的 clob 值。您可以就地执行此操作,只需使用 length() 函数 - 这对于 clob 非常有效。您使用什么版本的 Oracle?

标签: oracle plsql clob


【解决方案1】:

我对此有一点奇怪的决心,但它确实有效。

DECLARE 
JS CLOB;
BEGIN
  JS := TO_CLOB( 'THE FIRST PART OF CLOB SHOULD BE LESS THEN 32K
                  ......
                  ......'||
                 '....... 
                  THIS IS SECOND PART IS LESS THEN 32K TOO'||
                 '....... 
                  LAST PART');
END;

这种方式让我插入超过 1M

【讨论】:

    【解决方案2】:

    您收到 ORA-01704 是因为您的字符串文字超过 4000 个字节,这是 SQL 调用中字符串文字的大小限制。在 PL/SQL 中,限制为 32k,因此如果您的所有值都小于该值,您可以将它们分配给 PL/SQL 变量并将其用于插入:

    DECLARE
      newId NUMBER(38,0) := &1;
      newDescription varchar2(32767); -- or clob
    BEGIN
      newDescription := 'LARGE CLOB WHICH PRODUCES EXCEPTION';
      Insert into FOO ("ID", "DESCRIPTION")
      values (newId+1, newDescription);
    
      newDescription := 'ANOTHER LARGE CLOB WHICH PRODUCES EXCEPTION';
      Insert into FOO ("ID", "DESCRIPTION")
      values (newId+1, newDescription);
    
      ...
    END;
    /
    

    如果任何值超过 32k,您将需要一个 PL/SQL CLOB 变量,并且需要通过附加短 (

    使用多个插入语句可能不是最好的方法。您也许可以使用 SQL*Loader 或外部表来更简单地加载数据。或者您可以使用utl_file 读取值,例如到同一个 PL/SQL 变量中,然后在循环中插入 - 这将减少代码并且更易于维护。

    您还可以使用集合来保存字符串值:

    DECLARE
      TYPE stringTab IS table of varchar2(32767); -- or clob
      newDescriptions stringTab := new stringTab();
    BEGIN
      newDescriptions.extend;
      newDescriptions(newDescriptions.last) := 'LARGE CLOB WHICH PRODUCES EXCEPTION';
    
      newDescriptions.extend;
      newDescriptions(newDescriptions.last) := 'ANOTHER LARGE CLOB WHICH PRODUCES EXCEPTION';
    
      forall i in newDescriptions.first..newDescriptions.last
        insert into FOO ("ID", "DESCRIPTION")
        values (&1 + 1, newDescriptions(i));
    END;
    /
    

    ...这将是性能和(可能)可读性之间的权衡,与集合的内存使用情况。如果这对您的情况可行,您可以将其填充到块中,或者再次将值从文件中读取到集合中。


    您仍然可以通过对现有表的查询来生成它,例如:

    set pages 0
    set lines 32767
    set long 32767
    set define off
    
    select 'DECLARE' || chr(10)
      || '  newId NUMBER(38,0) := &1;' || chr(10)
      || '  newDescription varchar2(32767);' || chr(10)
      || 'BEGIN'
    from dual;
    
    select '  newDescription := q''[' || description || ']'';' || chr(10)
      || '  newId := newId + 1;' || chr(10)
      || '  insert into FOO ("ID", "DESCRIPTION") values (newId, newDescription);' || chr(10)
    from foo;
    
    select 'END;' || chr(10)
      || '/' || chr(10)
      || 'exit'
    from dual;
    
    set define on
    

    我使用the alternative quoting mechanism 以防您的任何字符串值包含单引号,但您需要选择合适的引号分隔符。再次假设您的 CLOB 值都不超过 32k。

    如果你真的想用一个充满插入语句的脚本来做这件事,我也会重新考虑;如果数据无论如何都来自表,那么导出/导入可能更合适。

    【讨论】:

    • 是的.. 我没有提到我从客户那里得到的 INSERT INTO 查询。我的意思是我可以向这个查询添加变量,但我没有输入 CLOB 变量,我只是将它作为文本获取。
    • 我可以操纵任何变量。我无法更改插入值,我得到它们是以前查询的结果
    • 你得到了整个脚本,就像你展示的那样,长字符串文字包含在 values 子句中,并且不能修改它?我糊涂了。获取插入值的前一个查询是什么?是在同一个数据库上运行,还是您可以链接到的数据库,或者您只能通过文件传输数据?
    • 我有选择查询来生成这个插入查询。像 Select ('Insert into .. values'field1, field2) FROM foo
    • @GrigoriyDidorenko - 您仍然可以从这样的查询中生成分配和插入语句。我添加了一个示例。
    【解决方案3】:

    您还可以在 PL/SQL 中声明一个 clob 变量。请参阅 lob semanticsDBMS_LOB 包来操作它。它可以是这样的:

    DECLARE
       myLOBFromDatabase CLOB;
    BEGIN
       SELECT lobComun INTO myLOBFromDatabase FROM table WHERE id=1;
    
    
       /* Manipulate lob wth dbms_lob package at will here */  
    
        Insert into FOO ("ID", "DESCRIPTION")
        values (newId+1, myLOBFromDatabase );
    
    END;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多