如何使用Oracle的LISTAGG函数和独特的过滤器?

发布于 2024-12-03 19:30:19 字数 649 浏览 0 评论 0原文

我有一个像这样的表:

group_id  name  
--------  ----
1         David
1         John
1         Alan
1         David
2         Julie
2         Charles

我想要以下结果:

group_id  names
--------  -----
1         'Alan, David, John'
2         'Charles, Julie'

我可以使用以下查询:

select group_id, 
       listagg(name, ',') within group (order by name) as names
from demotable
group by group_id 

要得到这个(非常相似的结果):

group_id  names
--------  -----
1         'Alan, David, David, John'
2         'Charles, Julie'

如何通过 LISTAGG 中的唯一性过滤名称的任何想法称呼?

I have a table like this:

group_id  name  
--------  ----
1         David
1         John
1         Alan
1         David
2         Julie
2         Charles

And I want the following result:

group_id  names
--------  -----
1         'Alan, David, John'
2         'Charles, Julie'

I can use the following query:

select group_id, 
       listagg(name, ',') within group (order by name) as names
from demotable
group by group_id 

To get this (very similar result):

group_id  names
--------  -----
1         'Alan, David, David, John'
2         'Charles, Julie'

Any ideas how I can filter the names by uniqueness in the LISTAGG call?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

你げ笑在眉眼 2024-12-10 19:30:19

我今天没有可用的 11g 实例,但您能不能使用:

SELECT group_id,
       LISTAGG(name, ',') WITHIN GROUP (ORDER BY name) AS names
  FROM (
       SELECT UNIQUE
              group_id,
              name
         FROM demotable
       )
 GROUP BY group_id

I don't have an 11g instance available today but could you not use:

SELECT group_id,
       LISTAGG(name, ',') WITHIN GROUP (ORDER BY name) AS names
  FROM (
       SELECT UNIQUE
              group_id,
              name
         FROM demotable
       )
 GROUP BY group_id
狼亦尘 2024-12-10 19:30:19

超级简单的答案 - 解决了!

我的完整答案这里现在在一些oracle版本中内置了。

select group_id, 
regexp_replace(
    listagg(name, ',') within group (order by name)
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
from demotable
group by group_id;  

仅当您将分隔符指定为 ',' 而不是 ', ' 时,这才有效,即
仅适用于逗号后不带空格的情况。如果您想在逗号后添加空格 - 这里是一个示例。

select 
replace(
    regexp_replace(
     regexp_replace('BBall, BBall, BBall, Football, Ice Hockey ',',\s*',',')            
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
,',',', ') 
from dual

给出
篮球、足球、冰球

Super simple answer - solved!

my full answer here it is now built in in some oracle versions.

select group_id, 
regexp_replace(
    listagg(name, ',') within group (order by name)
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
from demotable
group by group_id;  

This only works if you specify the delimiter to ',' not ', ' ie
works only for no spaces after the comma. If you want spaces after the comma - here is a example how.

select 
replace(
    regexp_replace(
     regexp_replace('BBall, BBall, BBall, Football, Ice Hockey ',',\s*',',')            
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
,',',', ') 
from dual

gives
BBall, Football, Ice Hockey

衣神在巴黎 2024-12-10 19:30:19
create table demotable(group_id number, name varchar2(100));
insert into demotable values(1,'David');
insert into demotable values(1,'John');
insert into demotable values(1,'Alan');
insert into demotable values(1,'David');
insert into demotable values(2,'Julie');
insert into demotable values(2,'Charles');
commit;

select group_id, 
       (select listagg(column_value, ',') within group (order by column_value) from table(coll_names)) as names
from (
  select group_id, collect(distinct name) as coll_names 
    from demotable
    group by group_id 
)

GROUP_ID    NAMES
1   Alan,David,John
2   Charles,Julie
create table demotable(group_id number, name varchar2(100));
insert into demotable values(1,'David');
insert into demotable values(1,'John');
insert into demotable values(1,'Alan');
insert into demotable values(1,'David');
insert into demotable values(2,'Julie');
insert into demotable values(2,'Charles');
commit;

select group_id, 
       (select listagg(column_value, ',') within group (order by column_value) from table(coll_names)) as names
from (
  select group_id, collect(distinct name) as coll_names 
    from demotable
    group by group_id 
)

GROUP_ID    NAMES
1   Alan,David,John
2   Charles,Julie
紧拥背影 2024-12-10 19:30:19
select group_id, 
       listagg(name, ',') within group (order by name) as names
       over (partition by group_id)   
from demotable
group by group_id 
select group_id, 
       listagg(name, ',') within group (order by name) as names
       over (partition by group_id)   
from demotable
group by group_id 
捂风挽笑 2024-12-10 19:30:19

以下内容未记录且不被 Oracle 推荐。
并且不能应用于函数,显示错误

select wm_concat(distinct name) as names from demotable group by group_id

问候
齐亚

below is undocumented and not recomended by oracle.
and can not apply in function, show error

select wm_concat(distinct name) as names from demotable group by group_id

regards
zia

情愿 2024-12-10 19:30:19

在基于最外层查询进行聚合之前,我需要这种和平的代码作为带有一些数据过滤器的子查询,但我无法使用所选的答案代码来执行此操作,因为此过滤器应该进入最内层的选择(第三级查询)并且过滤器参数位于最外层的选择(第一级查询)中,这给了我错误ORA-00904:“TB_OUTERMOST”。“COL”:无效标识符,因为ANSI SQL声明表引用(相关名称)的范围仅限于一层深度。

我需要一种没有子查询级别的解决方案,下面的这个解决方案对我来说非常有用:

with

demotable as
(
  select 1 group_id, 'David'   name from dual union all
  select 1 group_id, 'John'    name from dual union all
  select 1 group_id, 'Alan'    name from dual union all
  select 1 group_id, 'David'   name from dual union all
  select 2 group_id, 'Julie'   name from dual union all
  select 2 group_id, 'Charlie' name from dual
)

select distinct 
  group_id, 
  listagg(name, ',') within group (order by name) over (partition by group_id) names
from demotable
-- where any filter I want
group by group_id, name
order by group_id;

I needed this peace of code as a subquery with some data filter before aggregation based on the outer most query but I wasn't able to do this using the chosen answer code because this filter should go in the inner most select (third level query) and the filter params was in the outer most select (first level query), which gave me the error ORA-00904: "TB_OUTERMOST"."COL": invalid identifier as the ANSI SQL states that table references (correlation names) are scoped to just one level deep.

I needed a solution with no levels of subquery and this one below worked great for me:

with

demotable as
(
  select 1 group_id, 'David'   name from dual union all
  select 1 group_id, 'John'    name from dual union all
  select 1 group_id, 'Alan'    name from dual union all
  select 1 group_id, 'David'   name from dual union all
  select 2 group_id, 'Julie'   name from dual union all
  select 2 group_id, 'Charlie' name from dual
)

select distinct 
  group_id, 
  listagg(name, ',') within group (order by name) over (partition by group_id) names
from demotable
-- where any filter I want
group by group_id, name
order by group_id;
独行侠 2024-12-10 19:30:19

在 11g 中,您可以使用未记录的函数 wm_concat,如下所示:

     select wm_concat(distinct name) as names from demotable group by group_id

In 11g you can use the undocumented function wm_concat like this:

     select wm_concat(distinct name) as names from demotable group by group_id
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文