Разбить столбец на несколько строк в ORACLE на основе статической длины подстроки - PullRequest
0 голосов
/ 04 октября 2018

Я видел несколько тем здесь для "Разделить столбец на несколько строк", но все они основаны на некотором разделителе.

Я хочу разделить столбец по длине в oracle.

Предположим, у меня есть таблица

codes                     | product
--------------------------+--------
C111C222C333C444C555..... |  A   

коды типа VARCHAR2 (800) и продукт VARCHAR2 (1).

Здесь в поле кодов у нас есть много кодов (максимум 200), которые принадлежат продукту A. Длина каждого кода равна 4 (поэтому C111, C222, C333 - разные коды)

Мне нужен вывод моего запроса на выборку, подобный этому -

code          |  product
---------------+-------
C111           |    A
C222           |    A
C333           |    A
C444           |    A
C555           |    A
...

и т. Д.

, пожалуйста, помогите мне с этим.Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 04 октября 2018

Вот еще одна вариация, использующая regexp_substr () вместе с CONNECT BY для «цикла» по строке из 4-х символьных подстрок:

SQL> with tbl(codes, product) as (
     select 'C111C222C333C444C555', 'A' from dual union all
     select 'D111D222D333', 'B' from dual
   )
   select regexp_substr(codes, '(.{4})', 1, level, null, 1) code, product
   from tbl
   connect by level <= (length(codes)/4)
     and prior codes = codes
     and prior sys_guid() is not null;

CODE                 P
-------------------- -
C111                 A
C222                 A
C333                 A
C444                 A
C555                 A
D111                 B
D222                 B
D333                 B

8 rows selected.

SQL>
0 голосов
/ 04 октября 2018

Один из вариантов может быть таким:

SQL> with test (codes, product) as
  2    (select 'C111C222C333C444C555', 'A' from dual union all
  3     select 'D555D666D777', 'B' from dual
  4    )
  5  select substr(codes, 4 * (column_value - 1) + 1, 4) code, product
  6  from test,
  7       table(cast(multiset(select level from dual
  8                           connect by level <= length(codes) / 4
  9                          ) as sys.odcinumberlist))
 10  order by 1;

CODE P
---- -
C111 A
C222 A
C333 A
C444 A
C555 A
D555 B
D666 B
D777 B

8 rows selected.

SQL>
0 голосов
/ 04 октября 2018

Еще один немного другой вариант использования рекурсивного SQL для этого.(Чтобы сделать его более кратким, я не добавил пример тестовых данных. Он может быть взят из ответов @Littlefoot или @Peter)

select code, product
  from (
        select distinct
               substr(codes, (level - 1) * 4 + 1, 4) as code,
               level as l,
               product
          from YourTable
       connect by substr(codes, (level - 1) * 4 + 1, 4) is not null
       )
order by product, l 

PS @Thorsten Kettner справедливо высказался по поводу реструктуризацииваши столы.Это было бы правильно сделать для упрощения обслуживания вашей базы данных в будущем

0 голосов
/ 04 октября 2018

Вот как бы я это сделал.Дайте мне знать, если вам нужны дополнительные входные данные / более подробные объяснения:

select substr(tt.codes,(((t.l-1)*4)+1),4) code,tt.product from tst_tab tt
    join (select level l from dual connect by level <= (select max(length(codes)/4) from tst_tab)) t 
    on t.l <= length(tt.codes)/4 
order by tt.product,t.l;

Некоторые пояснения:

-- this part gives the numbers from 1 ... maximum number of codes in codes column
select level l from dual connect by level <= (select max(length(codes)/4) from tst_tab);
-- here is the query without the code extraction, it is just the numbers 1... numbers of codes for the product
select t.l,tt.product from tst_tab tt
    join (select level l from dual connect by level <= (select max(length(codes)/4) from tst_tab)) t 
    on t.l <= length(tt.codes)/4
order by tt.product,t.l;  
-- and then the substr just extracts the right code: 
substr(tt.codes,(((t.l-1)*4)+1),4)

Настройка данных моего теста:

create table tst_tab (codes VARCHAR2(800),product VARCHAR2(1));
insert into tst_tab values ('C111C222C333C444C555','A');
insert into tst_tab values ('C111C222C333C444C555D666','B');
insert into tst_tab values ('C111','C');
commit;
...