如何使用带有唯一过滤器的 Oracle 的 LISTAGG 函数? [复制]

Posted

技术标签:

【中文标题】如何使用带有唯一过滤器的 Oracle 的 LISTAGG 函数? [复制]【英文标题】:How to use Oracle's LISTAGG function with a unique filter? [duplicate] 【发布时间】:2011-11-13 09:09:52 【问题描述】:

我有一张这样的桌子:

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 调用中按唯一性过滤名称吗?

【问题讨论】:

查看这篇文章中接受的答案:dba.stackexchange.com/questions/696/… 不太一样。适用于这个问题的答案需要修改以回答另一个问题。这并不是说你不能在那里学到一些东西来解决这个问题.. 【参考方案1】:

我今天没有可用的 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

【讨论】:

这是我在这个问题上的第一个想法,并查看了链接的 DBA 问题。根据自动跟踪,在这个简单的数据上,成本是相同的。 感谢您的回答!这对于问题是正确的。不幸的是,我的问题表述不够精确,这对我的现实生活问题没有帮助,因为我需要该表中的其他列,我无法用 UNIQUE 运算符隐藏。 很好 - 很痛苦,但它有效。你应该看到我的查询,这只是一小部分 :D 哦,我们编织的网是多么纠结 :D【参考方案2】:

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

我的完整答案here 现在已内置在某些 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

给予 篮球、足球、冰球

【讨论】:

我使用过 Oracle 正则表达式,但我不是专家,我不知道这里发生了什么,尤其是模式字符串中的“\1”。有人可以解释一下这里发生了什么吗?提前致谢。 实际上,如果重复值不是 listagg 结果中的前 2 个值,这对我不起作用。例如:此体育作品列表(其中棒球重复):棒球、篮球 - 男子、足球、冰球 - 男子但这不:曲棍球、终极飞盘俱乐部 - 女子、终极飞盘俱乐部 - 女子 select regexp_replace('曲棍球,终极飞盘俱乐部 - 女子,终极飞盘俱乐部 - 女子','([^,]+)(,\1)+', '\1') from双回报曲棍球,终极飞盘俱乐部 - 女性似乎工作。 \1 是圆括号 ([^,]+) 中的第一个匹配项 - 除了逗号之外的任何内容。所以用 \1 替换 \1, \1 删除重复项。如果您不了解 regexp 是一种黑艺术,请不要担心。 你的权利还没来得及做呢..!【参考方案3】:
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

【讨论】:

【参考方案4】:
select group_id, 
       listagg(name, ',') within group (order by name) as names
       over (partition by group_id)   
from demotable
group by group_id 

【讨论】:

【参考方案5】:

以下内容未记录,oracle 不推荐。 并且不能在函数中应用,显示错误

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

问候 齐亚

【讨论】:

WM_concat 将无法在 oracle 12g 上默认使用,这是一个已弃用的功能。直到 11g 才能正常工作【参考方案6】:

在基于最外层查询进行聚合之前,我需要这种代码和平作为带有一些数据过滤器的子查询,但我无法使用所选答案代码执行此操作,因为此过滤器应该进入最内层选择(第三级别查询)并且过滤器参数位于最外层选择(第一级查询)中,这给了我错误 ORA-00904: "TB_OUTERMOST"."COL": invalid identifier 作为 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;

【讨论】:

【参考方案7】:

在 11g 中,您可以像这样使用未记录的函数 wm_concat:

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

【讨论】:

真的,不要使用WM_CONCAT!我被不同(次要!)版本的 Oracle(11.2.0.1 与 11.2.0.2,当 Oracle 决定 WM_CONCAT 应该返回 CLOB 类型)之间的行为变化所困扰 yes 返回一个 CLOB - 不是字符串 - 仅供参考 仅供参考 ... 12c 及更高版本不再支持。

以上是关于如何使用带有唯一过滤器的 Oracle 的 LISTAGG 函数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 中,这是带有过滤器的交叉连接还是内部连接?

Codeforces486 E. LIS of Sequence(LIS唯一性判断)

带有连接的Oracle,需要唯一性

带有 CLOB 数据点的 Oracle 复合主键

如何过滤我的表以在 Oracle 中显示结果?

使用 kerberos 和 AD 的 Oracle 数据库身份验证