【问题标题】:How to substitute with Comma Separate values in Oracle SQL如何在 Oracle SQL 中用逗号分隔值替换
【发布时间】:2021-11-10 12:01:18
【问题描述】:

我有一个类似下面的场景(Oracle 的 SQL)。

表:Employee

S.No Name Role
1 a ELE,PLU,OTH
2 b MAN,DIR
3 c DIR,FND
4 d

表:Role_master

Role Role name
ELE Electrician
PLU Plumber
MAN Manager
DIR Director
FND Founder
OTH Other

对于上面的表格,我想加入这两个表格,并期待如下所示的输出。请提供更好的方法。

S.No Name Role
1 a Electrician,Plumber,Other
2 b Manager,Director
3 c Director,Founder
4 d

【问题讨论】:

  • 在单列(您的 EMPLOYEE 表的 ROLE 列)中有一个以逗号分隔的值列表违反了数据设计的very first 规则。如果一个员工可以有多个角色,那么应该有第二个表,比如 EMP_ROLES,每个员工/角色组合有一行,还有一个返回 EMPLOYEE TABLE 的 FK。适当的数据设计使这样的问题变得微不足道,甚至使它们完全消失。你应该花一些时间研究数据标准化。

标签: sql oracle oracle11g


【解决方案1】:

这是一种选择:

  • #1 - 12 行中的样本数据;查询从第 14 行开始
  • employee.role 拆分为行(即单独的值),以便您可以将它们加入role_master.role
  • 将它们聚合回来(使用listagg

SQL> with
  2  employee (sno, name, role) as
  3    (select 1, 'a', 'ELE,PLU,OTH' from dual union all
  4     select 2, 'b', 'MAN,DIR'     from dual
  5    ),
  6  role_master (role, role_name) as
  7    (select 'ELE', 'Electrician' from dual union all
  8     select 'PLU', 'Plumber'     from dual union all
  9     select 'OTH', 'Other'       from dual union all
 10     select 'MAN', 'Manager'     from dual union all
 11     select 'DIR', 'Director'    from dual
 12    )
 13  --
 14  select e.sno,
 15         e.name,
 16         listagg(m.role_name, ',') within group (order by column_value) role
 17  from employee e cross join
 18    table(cast(multiset(select level from dual
 19                        connect by level <= regexp_count(e.role, ',') + 1
 20                       ) as sys.odcinumberlist))
 21    join role_master m on m.role = regexp_substr(e.role, '[^,]+', 1, column_value)
 22  group by e.sno, e.name;

       SNO NAME ROLE
---------- ---- ----------------------------------------
         1 a    Electrician,Plumber,Other
         2 b    Manager,Director

SQL>

【讨论】:

    【解决方案2】:

    另一个解决方案可以使用这个逻辑:

    1. 首先,生成拆分步骤所需的最大行数 (required_rows_v)
    2. 然后,在三个数据源之间进行左连接,如下所示
    3. 然后,使用 listagg 函数重新聚合行
    With required_rows_v (lvl) as (
    select level lvl
    from dual
    connect by level <= ( select max( regexp_count( e.Role, '[^,]+' )  )  from employee e )
    )
    select e.SNO,
          e.NAME,
        listagg(rm.Role_name, ',')within group (order by e.SNo, v.lvl) Role
    from employee e
    left join required_rows_v v on v.lvl <= regexp_count( e.Role, '[^,]+' )
    left join Role_master rm on rm.Role = regexp_substr( e.Role, '[^,]+', 1, v.lvl )
    group by e.SNO, e.NAME
    
    

    demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-01
      相关资源
      最近更新 更多