2017-01-19 5 views
-1

У меня есть таблица с именем LOG, которая имеет столбец с именем MESSAGE, который является VARCHAR2(4000). Поскольку я планирую миграцию, а столбец MESSAGE в новой базе данных - VARCHAR2(2000), я хочу перебрать все строки MESSAGE с длиной> 2000 и подстроить текст после 2000 символов и вставить весь текст, который приходит после 2000 символов в новую строку. Мне также нужно обновить исходные строки, чтобы иметь 2000 символов.Разбиение и вставка строки в PL/SQL

Как я могу это сделать? Прошло очень много времени с тех пор, как я работал с PL/SQL, я был бы очень признателен за вашу помощь.

+0

Предположим, вы это сделали. В новой базе данных, как вы узнаете, какая строка содержит первые 2000 символов, а какая строка содержит оставшуюся часть 'MESSAGE'? Вам нужна дополнительная колонка, чтобы показать «часть 1» и «часть 2»? Кажется, было бы намного проще изменить столбец в таблице «получение» на «VARCHAR2 (4000)», это опция? (Если нет, почему бы и нет?) – mathguy

+0

Существует также идентификатор сегмента, поэтому это не проблема. Я не могу изменить его на VARCHAR2 (4000) из-за кодировки символов. – Javiator

+0

Разве это не одна «вставка» и «обновление»? Я не вижу осложнений. –

ответ

1

Один метод:

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; 
+0

Большое спасибо за ваш ответ. Но как я могу вставить часть 'substr (l.message, 2001, 4000)' теперь в новую строку? – Javiator

+0

@Javiator. , , Вы можете поставить 'insert' перед этим оператором. –

+0

Как это выглядит? – Javiator

1

Она также может быть легко сделано с connect by, как это показано в этом примере, где он должен разделить после каждого 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 

Это может быть ваш окончательный выбор.

+0

Позиции символов в строках Oracle начинаются с 1, а не 0. Как вы это написали, первая строка будет иметь длину 4, а не 5. Чтобы исправить ее, добавьте 1 ко второму аргументу 'substr()'. – mathguy

0

Ваша проблема может быть решена с помощью блока 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> create table log(message varchar2(4000)); 

SQL> select message from log ; 

MESSAGE 
-------------------------------------------------------------------------------- 
KHAGDKAGDHAGDKHAGD 
ADSJHA:DAH:DHHAHDH 
. 
. 
. 
SQL> select length(message) from log ; 

LENGTH(MESSAGE) 
--------------- 
      3989 

SQL> create table table_log(col1 varchar2(2000)); 


SQL> select col1 from table_log ; 

COL1 
-------------------------------------------------------------------------------- 


SQL>/

PL/SQL procedure successfully completed. 

--- Two rows created to destination table with size approx 2000 characters each 
SQL> select length(col1) from table_log ; 

LENGTH(COL1) 
------------ 
     2000 
     1989 

В простом 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; 
+0

Большое спасибо за ваш ответ. Это решает проблему, однако в моей ситуации это не очень эффективно, так как у меня около 20 миллионов строк для обработки. – Javiator

+0

SQL всегда будет быстрее PLSQL. Я ответил, что вы упомянули, что хотите сделать в PLSQL. – XING

+0

Как бы вы это сделали в SQL? – Javiator

0

Вы можете разбить строки во время копирования в новую таблицу. Для этого вы должны использовать INSERT ALL WHEN. Для каждого предложения WHEN, условие которого равно true, база данных выполняет соответствующий список предложений 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; 

И результаты;

select long_msg,length(long_msg) from dest_test_table;

 Смежные вопросы

  • Нет связанных вопросов^_^