【问题标题】:Multiple comma separated lists to columns多个逗号分隔的列表到列
【发布时间】:2019-08-29 06:50:39
【问题描述】:

我正在尝试将列中的逗号分隔列表拆分为不同的行。例如:

with testdata(vala,valb,valc) as(
select
    '1,2,3,4' as vala,
    '5,6,7,8' as valb,
    '9,10,11' as valc
from dual)

使用上面的表格,我试图以 vala、valb 和 valc 是列的形式获取值,不同的逗号分隔值是行。如下图所示:

我已经查看了https://lalitkumarb.wordpress.com/2014/12/02/split-comma-delimited-string-into-rows-in-oracle/https://blogs.oracle.com/aramamoo/how-to-split-comma-separated-string-and-pass-to-in-clause-of-select-statement,但我似乎无法应用所描述的方法,因为我有更多列...

我需要进行这种转换的原因是为了在查询的下方使用 IN 表达式中的这些值。

【问题讨论】:

标签: sql oracle split


【解决方案1】:

无论“高度”列如何,这都应该有效。

with testdata(vala, valb, valc) as(
   select '1,2,3,4' as vala
         ,'5,6,7,8' as valb
         ,'9,10,11' as valc
     from dual
)
select regexp_substr(vala,'[^,]+', 1, level) as vala -- Pick the 
      ,regexp_substr(valb,'[^,]+', 1, level) as valb -- value at this 
      ,regexp_substr(valc,'[^,]+', 1, level) as valc -- position or null
  from testdata
  connect by regexp_substr(vala,'[^,]+', 1, level) is not null -- Generate one row if 
          or regexp_substr(valb,'[^,]+', 1, level) is not null -- any of the positions
          or regexp_substr(valc,'[^,]+', 1, level) is not null -- would have a value

【讨论】:

  • 我的更快更短。
  • @ErsinGülbahar 这不是同一个答案;你的使用多个连接,效率较低,而这个不需要任何连接。
【解决方案2】:

试试这个:

with testdata(vala,valb,valc)
 as(
select
    '1,2,3,4' as vala,
    '5,6,7,8' as valb,
    '9,10,11' as valc
from dual)
,
main as (
select rownum rn, 
regexp_substr(vala,'[^,]+', 1, level) data from
testdata
connect by  regexp_substr(vala,'[^,]+', 1, level) is not null
),
sub as (
select  rownum rn, 
regexp_substr(valb,'[^,]+', 1, level)data from
testdata
connect by  regexp_substr(valb,'[^,]+', 1, level) is not null
),
sub2 as (
select  rownum rn, 
regexp_substr(valc,'[^,]+', 1, level)data from
testdata
connect by  regexp_substr(valc,'[^,]+', 1, level) is not null
)
select 
main.data,
sub.data,
sub2.data
 from
main 
full outer join
sub on main.rn=sub.rn
full outer join
sub2 on main.rn=sub2.rn

【讨论】:

  • 这将创建所需的输出。此解决方案中的问题是我需要提前知道哪一列将包含最多的元素(主要)。有没有办法避免这种情况。当您加入 rownr 时,我将能够进行计数并添加一个虚拟列(具有必要的行数),但希望避免这种情况。
  • @M.Doe ,如果对你有用,你可以签名为正确
【解决方案3】:

一种只使用简单字符串函数(而不是慢速正则表达式)的解决方案,不需要任何连接,还可以处理多个输入行:

Oracle 设置

CREATE TABLE testdata (vala, valb, valc) AS
  SELECT '1,2,3,4','5,6,7,8', '9,10,11' FROM DUAL UNION ALL
  SELECT '12', '13,14,15,16', '' FROM DUAL;

查询

WITH data ( vala, valb, valc, starta, startb, startc, enda, endb, endc, rn, idx ) AS (
  SELECT vala,
         valb,
         valc,
         1,
         1,
         1,
         INSTR( vala, ',', 1 ),
         INSTR( valb, ',', 1 ),
         INSTR( valc, ',', 1 ),
         ROWNUM,
         1
  FROM   testdata
UNION ALL
  SELECT vala,
         valb,
         valc,
         CASE WHEN enda = 0 THEN 0 ELSE enda + 1 END,
         CASE WHEN endb = 0 THEN 0 ELSE endb + 1 END,
         CASE WHEN endc = 0 THEN 0 ELSE endc + 1 END,
         CASE WHEN enda = 0 THEN 0 ELSE INSTR( vala, ',', enda + 1 ) END,
         CASE WHEN endb = 0 THEN 0 ELSE INSTR( valb, ',', endb + 1 ) END,
         CASE WHEN endc = 0 THEN 0 ELSE INSTR( valc, ',', endc + 1 ) END,
         rn,
         idx + 1
  FROM   data
  WHERE  enda > 0
  OR     endb > 0
  OR     endc > 0
)
SELECT CASE
       WHEN starta = 0 THEN NULL
       WHEN enda   = 0 THEN SUBSTR( vala, starta )
                       ELSE SUBSTR( vala, starta, enda - starta )
       END AS vala,
       CASE
       WHEN startb = 0 THEN NULL
       WHEN endb   = 0 THEN SUBSTR( valb, startb )
                       ELSE SUBSTR( valb, startb, endb - startb )
       END AS valb,
       CASE
       WHEN startc = 0 THEN NULL
       WHEN endc   = 0 THEN SUBSTR( valc, startc )
                       ELSE SUBSTR( valc, startc, endc - startc )
       END AS valc
FROM   data
ORDER BY rn, idx;

输出

瓦拉 |阀 | VALC :--- | :--- | :--- 1 | 5 | 9 2 | 6 | 10 3 | 7 | 11 4 | 8 | 12 | 13 | | 14 | | 15 | | 16 |

db小提琴here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 2013-07-03
    • 1970-01-01
    • 2019-03-07
    相关资源
    最近更新 更多