错误:ORA-01704:字符串文字太长。动态地将CLOB分配给变量

时间:2016-05-20 09:47:00

标签: oracle plsql clob

我的问题非常重要。

我应该执行运行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查询之前重新分配变量,我该怎么做?

3 个答案:

答案 0 :(得分:4)

您正在获取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变量,并且需要通过附加短路(< 32k)字符串文字来构造它,这很麻烦。

使用多个插入语句可能不是最好的方法。您可以使用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。

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

答案 1 :(得分:0)

您还可以在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;

答案 2 :(得分:0)

对此我有一个奇怪的解决方法,但是它可以工作。

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