将多列中的逗号分隔值转换为行

时间:2016-10-20 15:53:03

标签: sql oracle oracle11g

我正在尝试从表中创建一个视图,该视图将多列中的逗号分隔值转换为Oracle中的行。

我已成功完成了一个专栏。但我不能用两三列来做。

我使用了以下脚本成功运行一列。

Create VIEW MULTITESET AS 
SELECT rownum AS ID1,Tagging.COMMENTS,Tagging.category,Tagging.STATUS,
        trim(regexp_substr(Tagging.OBJ_ID, '[^,]+', 1, lines.column_value)) OBJ_ID
    FROM Tagging,
      TABLE (CAST (MULTISET
      (SELECT LEVEL FROM dual
              CONNECT BY instr(Tagging.OBJ_ID, ',', 1, LEVEL - 1) > 0
      ) AS sys.odciNumberList ) ) lines
    ORDER BY id, lines.column_value

现在我需要对名为OBJname的第二列执行相同的操作,就像列OBJ_ID一样。

所以我尝试了一些愚蠢的东西,如下所示,这是行不通的。

Create VIEW MULTITESET AS 
SELECT rownum AS ID1,Tagging.COMMENTS,Tagging.category,Tagging.STATUS,
        trim(regexp_substr(Tagging.OBJ_ID, '[^,]+', 1, lines.column_value)) OBJ_ID
    FROM Tagging,
      TABLE (CAST (MULTISET
      (SELECT LEVEL FROM dual
              CONNECT BY instr(Tagging.OBJ_ID, ',', 1, LEVEL - 1) > 0
      ) AS sys.odciNumberList ) ) lines
    ORDER BY id, lines.column_value ,
     trim(regexp_substr(Tagging.OBJname , '[^,]+', 1, lines.column_value)) OBJname 
    FROM Tagging,
      TABLE (CAST (MULTISET
      (SELECT LEVEL FROM dual
              CONNECT BY instr(Tagging.OBJname , ',', 1, LEVEL - 1) > 0
      ) AS sys.odciNumberList ) ) lines
    ORDER BY id, lines.column_value

在坚果壳中,我希望下图中的tabel-A转换为表-B。我怎么能这样做?

See attached picture

我的实际查看查询是:

SELECT rownum AS TRACKID2, LEAPFROG_TAGGING.ID, LEAPFROG_TAGGING.CREATED_DATE,
  LEAPFROG_TAGGING.CREATED_BY, LEAPFROG_TAGGING.COMMENTS,
  leapfrog_tagging.category, LEAPFROG_TAGGING.STATUS, LEAPFROG_TAGGING.OBJ_NAME,
  trim(regexp_substr(LEAPFROG_TAGGING.OBJ_ID, '[^,]+', 1, lines.column_value)) OBJ_ID
FROM LEAPFROG_TAGGING,
TABLE (CAST (MULTISET (
    SELECT LEVEL FROM dual
    CONNECT BY instr(LEAPFROG_TAGGING.OBJ_ID, ',', 1, LEVEL - 1) > 0
  ) AS sys.odciNumberList ) ) lines
ORDER BY id, lines.column_value;

1 个答案:

答案 0 :(得分:1)

假设逗号分隔值的数量总是在两列中匹配(每个ID只有一个名称),并且您使用的是11gR2,则可以使用recursive subquery factoring

create view multiteset as
with t (obj_id, obj_name, status, other_columns, rn, orig_obj_id, orig_obj_name) as (
  select regexp_substr(obj_id, '[^,]+', 1, 1),
    regexp_substr(obj_name, '[^,]+', 1, 1),
    status, other_columns, 1, obj_id, obj_name
  from tagging
  union all
  select regexp_substr(orig_obj_id, '[^,]+', 1, rn + 1),
    regexp_substr(orig_obj_name, '[^,]+', 1, rn + 1),
    status, other_columns, rn + 1, orig_obj_id, orig_obj_name
  from t
  where rn < regexp_count(orig_obj_id, '[^,]+')
)
select obj_id, obj_name, status, other_columns
from t;

select * from multiteset;

OBJ_ID                       OBJ_NAME STATUS OTHER_
---------------------------- -------- ------ ------
1                            a        open   value1
1                            a        closed value2
4                            hj       na     value3
2                            s        open   value1
2                            s        closed value2
5                            hj       na     value3
3                            d        open   value1
6                            hj       na     value3
4                            f        open   value1
7                            hj       na     value3

10 rows selected. 

您的问题中的列名称有点不一致,因此您必须调整您的真实姓名。

锚成员从每个列表中获取第一个元素,并保留原始列表的副本,以及一个计数器,以查看我们所在的元素(从1开始)。

递归成员然后在每个列表中查找下一个(rn +)元素,除了计数器之外,将其余值保持不变。

针对CTE的最终查询然后只获取生成的值,忽略CTE跟踪的临时值(rnorig_obj_id等。)

您在评论中添加的新原始视图定义可能真的需要:

create view multiteset as
with t (id, created_date, created_by, comments, category, status,
  obj_name, obj_id, rn, orig_obj_name, orig_obj_id)
as (
  select id, created_date, created_by, comments, category, status,
    regexp_substr(obj_name, '[^,]+', 1, 1),
    regexp_substr(obj_id, '[^,]+', 1, 1),
    1, obj_name, obj_id
  from leapfrog_tagging
  union all
  select id, created_date, created_by, comments, category, status,
    regexp_substr(orig_obj_name, '[^,]+', 1, rn + 1),
    regexp_substr(orig_obj_id, '[^,]+', 1, rn + 1),
    rn + 1, orig_obj_name, orig_obj_id
  from t
  where rn < regexp_count(orig_obj_id, '[^,]+')
)
select id, created_date, created_by, comments, category, status,
  obj_name, obj_id
from t;

另请注意,没有order by条款;在视图定义中没有意义,并且应该在查询视图时应用:

select * from multiteset order by id, obj_id;

如果你想保留位置标记,那么也可以按顺序排列视图结果,然后在最终选择列表中包含rn(或更有意义的名字!),例如:

...
select id, rn as trackid2, created_date, created_by, comments, category, status,
  obj_name, obj_id
from t;

可以让你:

select * from multiteset order by id, trackid2;