如何将Oracle的LISTAGG函数与唯一筛选器一起使用?

如何将Oracle的LISTAGG函数与唯一筛选器一起使用?,oracle,group-by,oracle11g,aggregate-functions,Oracle,Group By,Oracle11g,Aggregate Functions,我有一张这样的桌子: group_id name -------- ---- 1 David 1 John 1 Alan 1 David 2 Julie 2 Charles select wm_concat(distinct name) as names from demotable group by group_id 我希望得到以下结果: group_id names ---

我有一张这样的桌子:

group_id  name  
--------  ----
1         David
1         John
1         Alan
1         David
2         Julie
2         Charles
     select wm_concat(distinct name) as names from demotable group by group_id
我希望得到以下结果:

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'

您知道如何在Listag调用中按唯一性筛选名称吗?

我现在没有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

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

group_id  name  
--------  ----
1         David
1         John
1         Alan
1         David
2         Julie
2         Charles
     select wm_concat(distinct name) as names from demotable group by group_id

超级简单的答案-解决

我的完整答案是,它现在内置在一些oracle版本中

select group_id, 
regexp_replace(
    listagg(name, ',') within group (order by name)
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
from demotable
group by group_id;  
这仅在将分隔符指定为“,”而不是“,”ie时有效 仅适用于逗号后没有空格的情况。如果你想在逗号后面加空格,下面是一个例子

select 
replace(
    regexp_replace(
     regexp_replace('BBall, BBall, BBall, Football, Ice Hockey ',',\s*',',')            
    ,'([^,]+)(,\1)*(,|$)', '\1\3')
,',',', ') 
from dual
给予
B足球、足球、冰球

我需要这种代码的和平,作为子查询,在基于最外层查询进行聚合之前使用一些数据过滤器,但我无法使用所选的答案代码来实现这一点,因为此过滤器应位于最内层的选择三级查询中,而过滤器参数位于最外层的选择一级查询中,这给了我错误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;

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

select wm_concat(distinct name) as names from demotable group by group_id
问候
齐亚

看看这篇文章中被接受的答案:不完全一样。。这个问题的答案需要修改以回答另一个问题。这并不是说你不能在那里学到一些东西来应用到这个问题上……这是我在这个问题上的第一个想法,看看相关的DBA问题。在这个简单的数据上,根据autotrace,成本是相同的。感谢您的回答!这是问题的正确答案。不幸的是,我的问题公式不够精确,这对我的实际问题没有帮助,因为我需要这个表中的其他列,我不能用唯一运算符隐藏。很好-很痛苦,但它可以工作。你应该看到我的疑问,这只是一小片:哦,我们编织了一张多么纠结的网:真无聊,不要用WM_CONCAT!我被它在不同小调之间的行为变化所咬!Oracle 11.2.0.1与11.2.0.2的版本,Oracle决定WM_CONCAT应返回CLOB类型Yes返回CLOB-不是字符串-仅供参考仅供参考。。。12c及更高版本不再支持。我使用Oracle regexp有一段时间了,但我不是专家,也不知道这里发生了什么,尤其是模式字符串中的\1。有人能解释一下这里发生了什么事吗?提前谢谢。事实上,如果重复的值不是listagg结果中的前2个值,那么这对我不起作用。例如:此运动列表适用于重复棒球的情况:棒球、篮球-男性、足球、冰球-男性,但不适用于:曲棍球、极限飞盘俱乐部-女性、极限飞盘俱乐部-女性选择regexp_替换“场地曲棍球、极限飞盘俱乐部-女性、极限飞盘俱乐部-女性”、“[^,]+、\1+”,“\1”来自双回程曲棍球,终极飞盘俱乐部-女性似乎很有用。\1是圆括号[^,]+中的第一个匹配词-除了逗号以外的任何词。因此,将\1\1替换为\1删除重复项。如果您不了解regexp是一门黑色艺术,请不要担心。您的权利人还没有时间去做它。。!defalut的WM_concat将无法在Oracle12g上工作,这是一个不推荐使用的函数。在11g之前,它可以正常工作