带名称/值列的oracle listagg

时间:2018-04-20 16:53:06

标签: oracle pivot listagg

我有桌子" foo"如下:

user_id attr_name    attr_value
-------------------------------
joe     user_id      abc123
joe     permission   A
joe     permission   B
joe     permission   C

我想要以下结果:

user_id       permission_List
-----------------------------
abc123        A, B, C

我可以通过以下非常简单的查询获得所需的结果:

select 
user_id,
LISTAGG(permissions,', ') within group(order by permissions) AS permission_list
from
(
    SELECT a1.attr_value AS user_id, 
    a2.attr_value AS permissions
    from foo a1 
    JOIN foo a2 on a1.user_id=a2.user_id
    WHERE a1.attr_name='user_id'
       and a2.attr_name='permission'
       and a1.user_id='joe'
)
group by user_id;

必须有一个更清洁的方式!有什么建议吗?

1 个答案:

答案 0 :(得分:2)

唉,PIVOT运算符不能与LISTAGG一起使用,所以你仍然需要使用旧的旋转方式(条件聚合)。但您可以简化查询,如下所示。

注意:在示例数据中,您有第一列名为USER_ID,值为“john” - 但是您有一个名为USER_ID的属性,其值为“abc123”。这是没有意义的。我在输出中使用了NEW_USER_ID的列名,但我希望在现实生活中你不必忍受这样的废话。

您在下面看到的WITH子句不是解决方案的一部分;我把它包括在内只用于测试。删除它,在剩下的查询中使用您的实际表和列名称。

with
  inputs ( user_id, attr_name, attr_value ) as (
    select 'joe', 'user_id'   , 'abc123' from dual union all
    select 'joe', 'permission', 'A'      from dual union all
    select 'joe', 'permission', 'B'      from dual union all
    select 'joe', 'permission', 'C'      from dual
  )
select   user_id,
         min(case attr_name when 'user_id' then attr_value end)      as new_user_id,
         listagg(case attr_name when 'permission' then attr_value end, ', ')
                                within group (order by attr_value)   as permission_list
from     inputs
where    attr_name in ('user_id', 'permission')
  and    user_id = 'joe'  --  if needed
group by user_id
;

USER_ID      NEW_USER_ID  PERMISSION_LIST   
------------ ------------ ------------------
joe          abc123       A, B, C