在oracle查询中使用长字符串(超过4000)

在oracle查询中使用长字符串(超过4000),oracle,plsql,varchar2,Oracle,Plsql,Varchar2,我知道在sql中,varchar2只能是4000左右 我知道在oracle PL中,varchcar2大约是32000 我定义了一个长度超过4000个字符的varchar2变量,我想在查询中使用它。我不想将值插入表中。该值是一个dilimited字符串,我正在解析该字符串并将其插入带有此查询的表中。当变量长度小于4000个字符时,此查询有效。有没有办法让它最多可以处理32000个字符 create global temporary table t(single_element varchar(5

我知道在sql中,varchar2只能是4000左右

我知道在oracle PL中,varchcar2大约是32000

我定义了一个长度超过4000个字符的varchar2变量,我想在查询中使用它。我不想将值插入表中。该值是一个dilimited字符串,我正在解析该字符串并将其插入带有此查询的表中。当变量长度小于4000个字符时,此查询有效。有没有办法让它最多可以处理32000个字符

create global temporary table t(single_element varchar(500),element_no number);
declare
--declared as 32767 but this string contains less than 4000 characters. 
--This will work. If you expand the string to 32000 characters it will not work.
myvar varchar2(32767) := 'tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4^~tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testmsg4';
begin
delete from t;
insert into t
SELECT SUBSTR(str, start_pos, (next_pos-start_pos)) AS single_element, element_no
FROM  (
        SELECT 
              ilv.str, 
              nt.column_value AS element_no, 
              INSTR(ilv.str, '^~', DECODE(nt.column_value, 1, 0, 1), DECODE(nt.column_value, 1, 1, nt.column_value-1)) + 2 AS start_pos,
              INSTR(ilv.str, '^~', 1, DECODE(nt.column_value, 1, 1, nt.column_value)) AS next_pos
        FROM   (
                select '~' || myvar || '^~' as str, 
                (Length(myvar) - length(replace(myvar,'^~','')))/2 + 2 as no_of_elements 
                from dual) ilv,

              TABLE(
                    CAST(
                       MULTISET(
                          SELECT ROWNUM FROM dual CONNECT BY ROWNUM < ilv.no_of_elements
                          ) AS number_ntt )) nt
         );
end;

有没有办法绕过这个大小限制,因为我实际上并没有将这个值插入表中,我只是在查询中使用它?

是否必须将变量定义为VARCHAR2?你能把它定义为CLOB吗

如果我将MYVAR的声明从VARCHAR232767更改为CLOB并定义NUMBER\u NTT类型,那么您的代码将为我运行

SQL> ed
Wrote file afiedt.buf

SP2-0161: line 2 truncated.
  1  declare
  2  myvar clob := 'tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3^~tcd4~#testms
  <<snip>>
~tcd3~#testmsg3^~tcd4~#testmsg4';
  4  begin
  5  delete from t;
  6  insert into t
  7  SELECT SUBSTR(str, start_pos, (next_pos-start_pos)) AS single_element, elem
ent_no
  8  FROM  (
  9          SELECT
 10                ilv.str,
 11                nt.column_value AS element_no,
 12                INSTR(ilv.str, '^~', DECODE(nt.column_value, 1, 0, 1), DECODE
(nt.column_value, 1, 1, nt.column_value-1)) + 2 AS start_pos,
 13                INSTR(ilv.str, '^~', 1, DECODE(nt.column_value, 1, 1, nt.colu
mn_value)) AS next_pos
 14          FROM   (
 15                  select '~' || myvar || '^~' as str,
 16                  (Length(myvar) - length(replace(myvar,'^~','')))/2 + 2 as n
o_of_elements
 17                  from dual) ilv,
 18                TABLE(
 19                      CAST(
 20                         MULTISET(
 21                            SELECT ROWNUM FROM dual CONNECT BY ROWNUM < ilv.n
o_of_elements
 22                            ) AS number_ntt )) nt
 23           );
 24* end;
 25  /

PL/SQL procedure successfully completed.

SQL> select count(*) from t;

  COUNT(*)
----------
       172

尽管如此,我并不是这样解析分隔字符串的,特别是在PL/SQL中。但是它确实起到了作用。

好吧,这就接近了实现偏差的边缘,尽管请记住forall是一个批量绑定操作,而不是一个真正的循环,但是您看过dbms_实用程序。逗号到表函数了吗

它是一个优化的内部oracle解析函数,但有一些限制,如您在此处所读到的:

如果解析的字段以数字、特殊字符开头、包含逗号等,则需要替换以逗号分隔,并用双引号括起来

但是,如果您的数据允许,它肯定会使您的代码看起来更干净,并且可能工作得更快

declare
   myvar      varchar2(32000) := 'tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3';
   mycnt      binary_integer;
   myresults  sys.dbms_utility.lname_array;
begin
   sys.dbms_utility.comma_to_table('"'||replace(myvar,'^~','","')||'"', mycnt, myresults );
   delete from t;
   forall ix in myresults.first..myresults.last 
      insert into tvalues (myresults(ix));
   commit;
end;

我试图想出一种比循环更有效的方法来解析字符串。这似乎比在分隔字符串中循环并分别插入每一行要快。关于如何解析字符串,你有其他想法吗?顺便说一下-我对非基于集合的操作有偏见。。。dbms本质上是以基于集合的方式运行的,我还没有看到使用循环比使用基于集合的解决方案有自然优势的例子。考虑到这一点,但是如果他们使用两个特殊字符作为分隔符,我猜这是因为他们不能保证数据不包含逗号。。。
declare
   myvar      varchar2(32000) := 'tcd1~#testmsg1^~tcd2~#testmsg2^~tcd3~#testmsg3';
   mycnt      binary_integer;
   myresults  sys.dbms_utility.lname_array;
begin
   sys.dbms_utility.comma_to_table('"'||replace(myvar,'^~','","')||'"', mycnt, myresults );
   delete from t;
   forall ix in myresults.first..myresults.last 
      insert into tvalues (myresults(ix));
   commit;
end;