如何使用带有唯一过滤器的 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 中,这是带有过滤器的交叉连接还是内部连接?