【问题标题】:Split column into multiple rows in ORACLE based on static length of substringORACLE中根据子字符串的静态长度将列拆分为多行
【发布时间】:2019-03-09 11:20:58
【问题描述】:

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

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

假设我有一张桌子

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

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

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

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

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

等等。

请帮我解决这个问题。提前致谢。

【问题讨论】:

  • 这不是关系数据库的使用方式。应该有一个包含产品代码的单独表格。可以修改数据库吗?那么你应该这样做。
  • 我想要我的选择查询中的输出...我不想改变表的结构。
  • 但你应该这样做。新表应该看起来像您显示的结果。建立关系数据库系统来关联表。使用您拥有的表,您没有正确使用 DBMS。您的表违反了数据库规范化。想一想:如果您已经有一个包含两个表而不是一个表的适当数据库,那么您甚至不会有任何问题。

标签: sql oracle oracle11g oracle12c


【解决方案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>

【讨论】:

    【解决方案2】:

    使用递归 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 
    

    附: @Thorsten Kettner 关于考虑重组您的表格提出了一个公平的观点。为了将来更容易维护您的数据库,这样做是正确的做法

    【讨论】:

      【解决方案3】:

      一个选项可能是这样的:

      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>
      

      【讨论】:

        【解决方案4】:

        我会这样做。如果您需要更多输入/更好的解释,请告诉我:

        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;
        

        【讨论】:

          猜你喜欢
          • 2022-11-18
          • 2022-11-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多