【问题标题】:converting multiple comma separated columns into rows将多个逗号分隔的列转换为行
【发布时间】:2017-12-14 12:00:14
【问题描述】:

我有一个 Oracle 表,其中包含许多列中的逗号分隔值。例如:

Id  Column1 Column2
1   A,B,C   H
2   D,E     J,K
3   F       L,M,N

我想将所有列拆分为行,输出应该是这样的:

ID  Column1 Column2
1      A       H
1      B       H
1      C       H
2      D       J
2      D       K
2      E       J
2      E       K
3      F       L
3      F       M
3      F       N

我发现了一些使用 regexp_substr 和 connect by 的建议,但它只处理一个具有逗号分隔值的列。我也尝试过子查询方法,我将在内部查询中一次处理一列,并将内部查询输出作为外部查询的输入发送,这需要更多时间,并且包含逗号分隔值的列更多。所以我不能使用子查询方法。

【问题讨论】:

    标签: oracle


    【解决方案1】:

    对于一列,您可以 CROSS JOIN 一个 TABLE() 集合表达式,其中包含一个相关子查询,该查询使用分层查询将列值拆分为单独的字符串。对于两列,您只需对第二列执行相同的操作,CROSS JOIN 负责确保column1 中的每个分隔值与column2 中的每个分隔值配对。

    SQL Fiddle

    Oracle 11g R2 架构设置

    CREATE TABLE table_name ( Id, Column1, Column2 ) AS
    SELECT 1, 'A,B,C', 'H' FROM DUAL UNION ALL
    SELECT 2, 'D,E',   'J,K' FROM DUAL UNION ALL
    SELECT 3, 'F',     'L,M,N' FROM DUAL;
    

    查询 1

    SELECT t.id,
           c1.COLUMN_VALUE AS c1,
           c2.COLUMN_VALUE AS c2
    FROM   table_name t
           CROSS JOIN
           TABLE(
             CAST(
               MULTISET(
                 SELECT REGEXP_SUBSTR( t.Column1, '[^,]+', 1, LEVEL )
                 FROM   DUAL
                 CONNECT BY LEVEL <= REGEXP_COUNT( t.Column1, '[^,]+' )
               ) AS SYS.ODCIVARCHAR2LIST
             )
           ) c1
           CROSS JOIN
           TABLE(
             CAST(
               MULTISET(
                 SELECT REGEXP_SUBSTR( t.Column2, '[^,]+', 1, LEVEL )
                 FROM   DUAL
                 CONNECT BY LEVEL <= REGEXP_COUNT( t.Column2, '[^,]+' )
               ) AS SYS.ODCIVARCHAR2LIST
             )
           ) c2
    

    Results

    | ID | C1 | C2 |
    |----|----|----|
    |  1 |  A |  H |
    |  1 |  B |  H |
    |  1 |  C |  H |
    |  2 |  D |  J |
    |  2 |  D |  K |
    |  2 |  E |  J |
    |  2 |  E |  K |
    |  3 |  F |  L |
    |  3 |  F |  M |
    |  3 |  F |  N |
    

    【讨论】:

    • 感谢您的即时回复,但这适用于 2 列。我有很多这样的专栏。多次交叉加入会有性能问题。您能否建议任何其他方法。 :)
    • @Bhavani 如果您想在没有CROSS JOIN 的情况下执行此操作,那么您需要指定一种方式,即为每一行指定column1 中分隔值的子集与@ 值的子集配对987654333@ 并与 column3 的值子集配对,否则,如果要将 column1 的一行中的每个分隔值与同一行中 column2 的每个分隔值配对,并将其与每个分隔值配对column3 在同一行中,那么您想要的是 CROSS JOIN!
    • @Bhavani 注意 - 表集合表达式与父行相关联,因此对于 ID=1,交叉联接将介于父查询的 1 行和 @987654340 的子查询的 3 行之间@ 和 1 行用于 column2 的子查询。相关性确保它只会生成配对分隔值的每个组合所需的最少行数。
    【解决方案2】:

    下面将为您介绍如何将逗号分隔的字符串转换为行。您可以使用此逻辑来满足您的需求。

    select regexp_substr('a,b,c,v,f', '[^,]+',1,level)
    from dual 
    connect by level <= regexp_count('a,b,c,v,f', ',') + 1;
    

    【讨论】:

    • 谢谢。但这仅适用于包含逗号分隔值的一列。
    • 你不能将同样的逻辑应用到另一列吗?
    猜你喜欢
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2012-12-02
    • 1970-01-01
    • 2021-09-06
    • 2016-01-29
    相关资源
    最近更新 更多