1

我在这里看到了“将列拆分为多行”的多个主题,但它们都基于一些分隔符。

我想根据 oracle 中的长度拆分列。

假设我有一张桌子

代码 | 产品
--------------+--------
C111C222C333C444C555..... | 一个   

代码是 VARCHAR2(800) 类型,产品是 VARCHAR2(1)。

在代码字段中,我们有许多代码(最多 200 个)属于产品 A。每个代码的长度为 4(因此 C111、C222、C333 是不同的代码)

我想要像这样输出我的选择查询-

代码 | 产品
---------------+--------
C111 | 一个
C222 | 一个
C333 | 一个
C444 | 一个
C555 | 一个
...

等等。

请帮我解决一下这个。提前致谢。

4

4 回答 4

1

这是使用 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>
于 2018-10-04T13:18:30.147 回答
0

这是我将如何做到的。如果您需要更多输入/更好的解释,请告诉我:

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;
于 2018-10-04T07:13:45.250 回答
0

使用递归 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 对考虑重组您的表格提出了一个公平的观点。为了将来更容易维护数据库,这将是正确的做法

于 2018-10-04T12:04:31.397 回答
0

一种选择可能是这样的:

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>
于 2018-10-04T07:16:33.910 回答