在Oracle中使用LISTAGG函数返回不重复的值。
在Oracle中使用LISTAGG函数返回不重复的值。
我试着在Oracle中使用LISTAGG
函数。我想要获取该列的唯一值。有没有一种方法可以在不创建函数或过程的情况下仅获取唯一值?
col1 col2 Created_by1 2 Smith
1 2 John
1 3 Ajay
1 4 Ram
1 5 Jack
我需要选择col1和col2的LISTAGG
(不考虑第3列)。当我这样做时,LISTAGG
的结果如下:[2,2,3,4,5]。
我需要移除这里重复的\'2\',我仅需要col1对应的col2的唯一值。
从Oracle 19C开始,它是内置的,请参见此处
从18C及更早版本,请尝试使用Within Group,请参见此处
否则,请使用正则表达式
以下是解决问题的方法。
select regexp_replace( '2,2,2.1,3,3,3,3,4,4' ,'([^,]+)(,\1)*(,|$)', '\1\3') from dual
返回
2,2.1,3,4
下面是答案:
select col1, regexp_replace( listagg( col2 , ',') within group (order by col2) -- sorted ,'([^,]+)(,\1)*(,|$)', '\1\3') ) from tableX where rn = 1 group by col1;
注意:上述方法在大多数情况下都可行-列表应该进行排序,根据您的数据,您可能需要修剪所有尾随和前导空格。
如果您在一组中有很多项目> 20或字符串大小很大,则可能会遇到Oracle字符串大小限制“字符串连接的结果太长”。
从Oracle 12cR2开始,您可以消除此错误,请参见此处。或者在每个组中放置最大数量的成员。如果只列出第一个成员是可以的,那么这只能起作用。如果您有非常长的可变字符串,则可能不起作用。您将不得不进行实验。
select col1, case when count(col2) < 100 then regexp_replace( listagg(col2, ',') within group (order by col2) ,'([^,]+)(,\1)*(,|$)', '\1\3') else 'Too many entries to list...' end from sometable where rn = 1 group by col1;
另一个解决方案(不是很简单),希望避免Oracle字符串大小限制-字符串大小受到限制为4000。感谢user3465996在此处的帖子
select col1 , dbms_xmlgen.convert( -- HTML decode dbms_lob.substr( -- limit size to 4000 chars ltrim( -- remove leading commas REGEXP_REPLACE(REPLACE( REPLACE( XMLAGG( XMLELEMENT("A",col2 ) ORDER BY col2).getClobVal(), '',','), '',''),'([^,]+)(,\1)*(,|$)', '\1\3'), ','), -- remove leading XML commas ltrim 4000,1) -- limit to 4000 string size , 1) -- HTML.decode as col2 from sometable where rn = 1 group by col1;
V1-一些测试情况-FYI
regexp_replace('2,2,2.1,3,3,4,4','([^,]+)(,\1)+', '\1') -> 2.1,3,4 Fail regexp_replace('2 ,2 ,2.1,3 ,3 ,4 ,4 ','([^,]+)(,\1)+', '\1') -> 2 ,2.1,3,4 Success - fixed length items
V2-包含在项内的项,例如2,21
regexp_replace('2.1,1','([^,]+)(,\1)+', '\1') -> 2.1 Fail regexp_replace('2 ,2 ,2.1,1 ,3 ,4 ,4 ','(^|,)(.+)(,\2)+', '\1\2') -> 2 ,2.1,1 ,3 ,4 -- success - NEW regex regexp_replace('a,b,b,b,b,c','(^|,)(.+)(,\2)+', '\1\2') -> a,b,b,c fail!
v3-正则表达式谢谢Igor! 适用于所有情况。
select regexp_replace('2,2,2.1,3,3,4,4','([^,]+)(,\1)*(,|$)', '\1\3') , ---> 2,2.1,3,4 works regexp_replace('2.1,1','([^,]+)(,\1)*(,|$)', '\1\3'), --> 2.1,1 works regexp_replace('a,b,b,b,b,c','([^,]+)(,\1)*(,|$)', '\1\3') ---> a,b,c works from dual
19c及其之后版本:
select listagg(distinct the_column, ',') within group (order by the_column) from the_table
18c及其之前版本:
select listagg(the_column, ',') within group (order by the_column) from ( select distinct the_column from the_table ) t
如果您需要更多列,可能会需要类似以下内容:
select col1, listagg(col2, ',') within group (order by col2) from ( select col1, col2, row_number() over (partition by col1, col2 order by col1) as rn from foo order by col1,col2 ) where rn = 1 group by col1;