【问题标题】:How to use listagg properly with case statements如何在 case 语句中正确使用 listagg
【发布时间】:2020-04-21 04:42:46
【问题描述】:

我正在尝试使用 listagg,但我得到了错误的输出。通常,我会单独使用每个 case 语句,但是我将如何使用 listagg 呢?

表 A:

 JAN     FEB    MAR    APR    Tag
 C                            102
          D            T      100
          D                   101
 C        D      B     T      103                  

表 B:

 Name       Tag
 Ally       100
 Ben        101
 Missy      102
 Noah       103

期望的输出:

 Ally  Dog,Turtle
 Ben   Dog
 Missy Chicken
 Noah  Chicken,Dog,Bird,Turtle

我尝试的(错误)代码:

 select listagg(
   nvl(
     case when a.jan = 'C' then 'Chicken'
          when a.feb = 'D' then 'Dog'
          when a.mar = 'B' then 'Bird'
          when a.apr = 'T' then 'Turtle'
      end,','),'none')
  within group (order by a.tag)
      from a where a.tag = b.tag 

【问题讨论】:

  • 您如何从您发布的输入中获取'Dog''Turtle' 之类的字符串?我在输入中看到了一些单字母字符串,例如 'C''D',但你怎么知道这些是鸡和狗,而不是猫和驴?
  • 这些只是我们收养的所有动物:D

标签: sql oracle listagg


【解决方案1】:

您可以通过在子查询中取消透视来构造查询:

select b.Name, a.*
  from b
  join
  (
  select tag, listagg( case
                       when val = 'C' then
                        'Chicken'
                       when val = 'D' then
                        'Dog'
                       when val = 'B' then
                        'Bird'
                       when val = 'T' then
                        'Turtle'
                       end,',') within group (order by 1) as animals
    from a
   unpivot ( val for name in (jan as 'JAN', feb as 'FEB', mar as 'MAR', apr as 'APR') )
   group by tag ) a
     on b.tag = a.tag   
  order by a.tag  

Demo

【讨论】:

  • 哦,非常好,从未听说过 unpivot!很高兴知道!
  • 很高兴听到@BFF
【解决方案2】:

这是一个选项,它使用多个自联接。

  • 第 1 - 14 行代表您的样本数据
  • anima CTE 在这里简化代码;比使用CASE 更好地将它放在一个表中(即使它是一个 CTE)
  • 最终结果,第 #24 - 34 行,连接动物名称
    • trim + regexp_replace 用于去除多余的逗号

给你:

SQL> with
  2  -- sample data
  3  taba (jan, feb, mar, apr, tag) as
  4    (select 'c' , null, null, null, 102 from dual union all
  5     select null, 'd' , null, 't' , 100 from dual union all
  6     select null, 'd' , null, null, 101 from dual union all
  7     select 'c' , 'd' , 'b' , 't' , 103 from dual
  8    ),
  9  tabb (name, tag) as
 10    (select 'ally' , 100 from dual union all
 11     select 'ben'  , 101 from dual union all
 12     select 'missy', 102 from dual union all
 13     select 'noah' , 103 from dual
 14    ),
 15  --
 16  -- replace animal codes with their names
 17  anima (code, name) as
 18    (select 'c', 'chicken' from dual union all
 19     select 'd', 'dog'     from dual union all
 20     select 'b', 'bird'    from dual union all
 21     select 't', 'turtle'  from dual
 22    )
 23  -- the final result
 24  select b.name,
 25    trim(',' from regexp_replace(n1.name ||','|| n2.name ||','|| n3.name ||','|| n4.name,
 26                                 '( *, *){2,}', ','
 27                                )
 28        ) result
 29  from tabb b join taba a on a.tag = b.tag
 30  left join anima n1 on n1.code = a.jan
 31  left join anima n2 on n2.code = a.feb
 32  left join anima n3 on n3.code = a.mar
 33  left join anima n4 on n4.code = a.apr
 34  order by b.name;

NAME  RESULT
----- ------------------------------
ally  dog,turtle
ben   dog
missy chicken
noah  chicken,dog,bird,turtle

SQL>

【讨论】:

  • 好吧,如果我不能强制 listagg,这会做 :) 谢谢!
  • 不客气。您可以在一系列 4 个 UNION 语句中使用 LISTAGG 执行此操作,每个语句选择人名和一个动物,以便 LISTAGG 然后将每个人的结果分组,以动物名称作为参数。
【解决方案3】:
with
-- sample data
taba (jan, feb, mar, apr, tag) as
  (select 'c' , null, null, null, 102 from dual union all
   select null, 'd' , null, 't' , 100 from dual union all
   select null, 'd' , null, null, 101 from dual union all
   select 'c' , 'd' , 'b' , 't' , 103 from dual
  ),
tabb (name, tag) as
  (select 'ally' , 100 from dual union all
   select 'ben'  , 101 from dual union all
   select 'missy', 102 from dual union all
   select 'noah' , 103 from dual
  ),
  tabab as (
   --select a.tag, b.name, nvl(a.jan,'na') as jan, nvl(a.feb,'na') as feb, nvl(a.mar,'na') as mar, nvl(a.apr,'na') as apr
   select 
      a.tag, b.name, 
      decode(a.jan,'b','bird','c','chicken','d','dog','t','turtle',null) as jan,
      decode(a.feb,'b','bird','c','chicken','d','dog','t','turtle',null) as feb,
      decode(a.mar,'b','bird','c','chicken','d','dog','t','turtle',null) as mar,
      decode(a.apr,'b','bird','c','chicken','d','dog','t','turtle',null) as apr
   from taba a   
   join tabb b
     on a.tag = b.tag
  )
  select 
      name,
      listagg(val,',') WITHIN GROUP (ORDER by decode(mon, 'JAN',1,'FEB',2,'MAR',3,'APR',4,null)) as listval
   from tabab
   unpivot
   (
     val
       for mon in (jan,feb,mar,apr)
   )
   group by name
   order by 1
;

【讨论】:

    猜你喜欢
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多