在PL/SQL中拆分和插入字符串

在PL/SQL中拆分和插入字符串,sql,oracle,plsql,oracle11g,Sql,Oracle,Plsql,Oracle11g,我有一个名为LOG的表,其中有一列名为MESSAGE,它是VARCHAR2(4000)。 由于我正在计划迁移,而新数据库中的MESSAGE列是VARCHAR2(2000),因此我希望迭代所有MESSAGE行,长度>2000,并将2000个字符后的文本子字符串插入新行。 我还必须更新原始行,使其具有2000个字符 我该怎么做?我已经很久没有使用PL/SQL了,非常感谢您的帮助。一种方法是: select . . ., substr(l.message, 1, 2000) as message fr

我有一个名为
LOG
的表,其中有一列名为
MESSAGE
,它是
VARCHAR2(4000)
。 由于我正在计划迁移,而新数据库中的
MESSAGE
列是
VARCHAR2(2000)
,因此我希望迭代所有
MESSAGE
行,长度>2000,并将2000个字符后的文本子字符串插入新行。 我还必须更新原始行,使其具有2000个字符

我该怎么做?我已经很久没有使用PL/SQL了,非常感谢您的帮助。

一种方法是:

select . . ., substr(l.message, 1, 2000) as message
from log l
union all
select . . ., substr(l.message, 2001, 2000) as message
from log l
where lenght(l.message) > 2000;

也可以使用
connectby
轻松完成此操作,如本例所示,它应在每5个字符后拆分:

select substr(test.test, (level-1)*5, 5)
from (select 'THIS IS A LONG MESSAGE ACTUALLY' test from dual) test
connect by substr(test.test, (level-1)*5, 5) IS NOT NULL
在这种情况下,您甚至不必担心任何事情,因为它会自动地分离值,无论它们是否长于2000

select substr(l.message, (level-1)*2000, 2000) message
from log l
substr(l.message, (level-1)*2000, 2000) IS NOT NULL

这可能是您的最终选择。

您的问题可以使用
PLSQL
块解决,如下所示。请尝试内联实现上述逻辑,并检查其是否有效

代码:

 declare
  ---getting each message of length 4000 characters
  cursor cur is 
  select message 
  from log;

   var number;                 
   var1 varchar2(2000);
   cntr number:=0;
begin
  --Loop for each message 
  for i in cur
   loop                
      --getting length of message
     var:= length(i.message);

       for len in 1..(var / 2000)
        loop
            --setting the offset to pick 2000 chracters
            if cntr = 0 then
             cntr := cntr +1;
            else 
              cntr := cntr + 2000;
            end if;  

            --selecting 2000 characters from message 
            var1:=substr(i.message,cntr,2000);

             ---inserting 2000 charcters to table
            insert into table_log(col1) 
            values(var1 );

             commit;
        end loop;

    end loop;

end;
演示:

在简单SQL中,您可以按如下方式执行

insert into table_log(col1) 
select SUBSTR(l.MESSAGE, 1, 2000) AS MESSAGE
FROM LOG l
UNION ALL
select  SUBSTR(l.MESSAGE, 2001, 2000) AS MESSAGE
FROM LOG l
WHERE length(l.MESSAGE) > 2000;

您可以在复制到新表的过程中拆分行。为此,您应该使用
插入所有WHEN
。对于条件计算为true的每个WHEN子句,数据库执行相应的INTO子句列表

create table src_test_table(long_msg varchar2(20));
create table dest_test_table(long_msg varchar2(10));

insert into src_test_table values(lpad('1',20,'1'));
insert into src_test_table values(lpad('2',20,'2'));
insert into src_test_table values(lpad('3',20,'3'));
insert into src_test_table values(lpad('4',10,'4'));
insert into src_test_table values(lpad('5',10,'5'));

insert all 
 when length(long_msg) <= 10 then 
    into dest_test_table values(long_msg)
 when length(long_msg) > 10 then 
    into dest_test_table values(substr(long_msg,1,10))   
 when length(long_msg) > 10 then 
    into dest_test_table values(substr(long_msg,11))   
select long_msg from  src_test_table;
create table src_test_table(long_msg varchar2(20));
创建表dest_test_table(long_msg varchar2(10));
在src_test_表中插入值(lpad('1',20,'1');
在src_测试_表中插入值(lpad('2',20,'2');
插入src_测试_表值(lpad('3',20,'3');
在src_测试_表中插入值(lpad('4',10,'4');
在src_测试_表中插入值(lpad('5',10,'5');
全部插入
当长度(long_msg)为10时
输入dest_test_表值(substr(long_msg,1,10))
当长度(long_msg)>10时
输入dest_test_表值(substr(long_msg,11))
从src_test_表中选择long_msg;
和结果


从dest\u test\u表中选择long\u msg、length(long\u msg)

非常感谢您的回答。但是我现在如何才能将
substr(l.message,2001,4000)
部分插入到新行中呢?@Javiator。你可以把
insert
放在这个语句前面。看起来怎么样?假设你这样做。在新数据库中,您如何知道哪一行包含前2000个字符,哪一行包含
消息的剩余部分?您是否需要另外一列来显示
第1部分
第2部分
?似乎将“receiving”表中的列更改为
VARCHAR2(4000)
要容易得多,这是一个选项吗?(如果没有,为什么没有?)还有一个段ID,因此这不是问题。由于字符编码,我无法将其更改为VARCHAR2(4000)。它不是只有一个
insert
和一个
update
?我看不出有什么复杂的地方。教育他人遵守礼仪是每个人的社会责任,所以请阅读本文,非常感谢您的回答。这解决了问题,但是在我的情况下,这不是很有效,因为我有大约2000万行要处理。SQL总是比PLSQL快。我回答了,因为你提到你想在PLSQL中执行。你会如何在SQL中执行?对。它不会更新原始行。它会为目标表中的每一行插入两行。是的,我看到了。但我必须先在我的源表上这样做。很抱歉,我想我忘了提到这一点。Oracle字符串中的字符位置以1开头,而不是0。按照您编写的方式,第一个字符串的长度为4,而不是5。要解决此问题,请在
substr()
的第二个参数中添加1。
create table src_test_table(long_msg varchar2(20));
create table dest_test_table(long_msg varchar2(10));

insert into src_test_table values(lpad('1',20,'1'));
insert into src_test_table values(lpad('2',20,'2'));
insert into src_test_table values(lpad('3',20,'3'));
insert into src_test_table values(lpad('4',10,'4'));
insert into src_test_table values(lpad('5',10,'5'));

insert all 
 when length(long_msg) <= 10 then 
    into dest_test_table values(long_msg)
 when length(long_msg) > 10 then 
    into dest_test_table values(substr(long_msg,1,10))   
 when length(long_msg) > 10 then 
    into dest_test_table values(substr(long_msg,11))   
select long_msg from  src_test_table;