如何在两列中使用Oracle的LISTAGG功能?

时间:2015-07-31 15:42:49

标签: oracle

我找到了关于comma separated list of values in Oracle的非常好的文章。

我想尝试一下,但是有两列而不是一列,就像数据一样:

+---+---------+---------+
| 1 | a, b, c | A, B    |
| 2 | a, b    | A, B, C |
+---+---------+---------+

我想得到结果:

over

我遇到的第一个问题是使用ORA-00979: not a GROUP BY expression部分......

甚至,当我看到documentation和多个例子时,f.e。 here

我无法解决with demotable as ( select 1 v1, 'a' v2, 'A' v3 from dual union all select 1 v1, 'a' v2, 'B' v3 from dual union all select 1 v1, 'b' v2, 'A' v3 from dual union all select 1 v1, 'b' v2, 'B' v3 from dual union all select 1 v1, 'c' v2, 'A' v3 from dual union all select 1 v1, 'c' v2, 'B' v3 from dual union all select 2 v1, 'a' v2, 'A' v3 from dual union all select 2 v1, 'a' v2, 'B' v3 from dual union all select 2 v1, 'a' v2, 'C' v3 from dual union all select 2 v1, 'b' v2, 'A' v3 from dual union all select 2 v1, 'b' v2, 'B' v3 from dual union all select 2 v1, 'b' v2, 'C' v3 from dual ) select v1 , LISTAGG ( v3, ', ' ) within group ( order by v3 ) over ( partition by v1 ) AS v3_list from demotable group by v1 ; 问题:

with demotable as ( ... )
select v1 
     , LISTAGG (
          v2, ', '
       ) within group (
          order by v2
       ) AS v2_list
     , LISTAGG (
          v3, ', '
       ) within group (
          order by v3
       ) AS v3_list
  from demotable
 group by v1
;
基于其他例子的

应该有效。

我想到的第一个解决方案是无法正常工作

+---+------------------+------------------+
| 1 | a, a, b, b, c, c | A, A, A, B, B, B |
| 2 | a, a, a, b, b, b | A, A, B, B, C, C |
+---+------------------+------------------+

因为它返回:

Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

我的Oracle版本是12c。

with demotable as ( ... )
select v1
     , LISTAGG (
          v2, ', '
       ) within group (
          order by v2
       ) AS v2_list
     , v3_list
  from (
    select v1
         , v2
         , LISTAGG (
              v3, ', '
           ) within group (
              order by v3
           ) AS v3_list
      from demotable
     group by v1, v2
) group by v1, v3_list
;

我发现只选择了选择的丑陋解决方案:

group by

删除其评论的人建议对所有列使用with demotable as ( ... ) select distinct v1 , LISTAGG ( v2, ', ' ) WITHIN GROUP ( ORDER BY v2 ) over ( partition by v1, v3 ) AS v2_list , LISTAGG ( v3, ', ' ) WITHIN GROUP ( ORDER BY v3 ) over ( partition by v1, v2 ) AS v2_list from demotable group by v1, v2, v3 ; ,这会引导我找到这个解决方案:

distinct

但如果没有必要,我不是{{1}}的粉丝。

2 个答案:

答案 0 :(得分:1)

使用这个非常好的answer

select v1 
,RTRIM(
         REGEXP_REPLACE(
           (listagg(v3,',') WITHIN GROUP (ORDER BY v3) ), 
           '([^,]*)(,\1)+($|,)', 
           '\1\3'),
         ',') as v3group
  ,RTRIM(
         REGEXP_REPLACE(
           (listagg(v2,',') WITHIN GROUP (ORDER BY v2) ), 
           '([^,]*)(,\1)+($|,)', 
           '\1\3'),
         ',') as v2group
  from demotable
  GROUP BY v1
;

FIDDLE

答案 1 :(得分:1)

假设我正确理解您的要求,我认为这符合您的要求:

with demotable as (select 1 v1, 'a' v2, 'A' v3 from dual union all
                   select 1 v1, 'a' v2, 'B' v3 from dual union all
                   select 1 v1, 'b' v2, 'A' v3 from dual union all
                   select 1 v1, 'b' v2, 'B' v3 from dual union all
                   select 1 v1, 'c' v2, 'A' v3 from dual union all
                   select 1 v1, 'c' v2, 'B' v3 from dual union all
                   select 2 v1, 'a' v2, 'A' v3 from dual union all
                   select 2 v1, 'a' v2, 'B' v3 from dual union all
                   select 2 v1, 'a' v2, 'C' v3 from dual union all
                   select 2 v1, 'b' v2, 'A' v3 from dual union all
                   select 2 v1, 'b' v2, 'B' v3 from dual union all
                   select 2 v1, 'b' v2, 'C' v3 from dual),
           res as (select v1,
                          case when row_number() over (partition by v1, v2 order by v3) = 1 then v2 end v2,
                          case when row_number() over (partition by v1, v3 order by v2) = 1 then v3 end v3
                   from   demotable)
select v1,
       listagg(v2, ', ') within group (order by v2) v2_list,
       listagg(v3, ', ') within group (order by v2) v3_list
from   res
group by v1;

        V1 V2_LIST    V3_LIST   
---------- ---------- ----------
         1 a, b, c    A, B      
         2 a, b       A, B, C  

res子查询只需要在v2和v3列中显示每个值的一个实例,这样就可以将一个不同值列表传递给每个listagg。

相关问题