如何把某一列的值去除重复并拼接显示

[复制链接]
查看11 | 回复9 | 2017-1-11 08:23:59 | 显示全部楼层 |阅读模式
本帖最后由 blueshuzi 于 2012-12-12 16:53 编辑
rt
如果是像表tmp_suu 的数据的话 要求查询结果: 去除重复值,并且按照从小到大的顺序排列 。

正确结果 应该是001,002,004

数据
SQL> select * from tmp_suu;

VV
----
001
001
002
004
002
004
001
004

我使用了COLLECT进行收集和排序处理
结果虽然排序了,但是没有去除重复
SQL> SELECT concat_array(CAST(COLLECT(DISTINCT u.vv ORDER BY
2
u.vv) AS strarray),
3
',')
4FROM tmp_suu u;

CONCAT_ARRAY(CAST(COLLECT(DIST
--------------------------------------------------------------------------------
001,001,001,002,002,004,004,004

如果去掉 ORDER BY部分,就可以去除重复数据
SQL>
SQL> SELECT concat_array(CAST(COLLECT(DISTINCT u.vv) AS strarray),
2
',')
3FROM tmp_suu u;

CONCAT_ARRAY(CAST(COLLECT(DIST
--------------------------------------------------------------------------------
001,002,004
想问下,为什么加上order by 就不能去除重复了呢?
应该怎么做才能得出正确的查询结果呢。
希望sql尽量简单点,因为真实表数据量很大。

strarray 是个简单的 varchar2 table 类型
CREATE OR REPLACE TYPE "STRARRAY"AS TABLE OF VARCHAR2(4000 BYTE);
concat_array 是将 strarray 转成 VARCHAR2 输出的一个函数
代码如下
CREATE OR REPLACE FUNCTION concat_array(i_strarrayIN strarray,

i_delimiter IN VARCHAR2 DEFAULT NULL)
RETURN VARCHAR2 IS
l_str VARCHAR2(4000);
BEGIN
IF i_strarray IS NULL OR i_strarray.COUNT = 0 THEN
RETURN '';
END IF;
l_str := i_strarray(1);
FOR i IN 2 .. i_strarray.COUNT LOOP
l_str := l_str || i_delimiter || i_strarray(i);
END LOOP;
RETURN l_str;
END concat_array;

当前db版本
Release 11.2.0.2.0


回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
SELECT concat_array(CAST(COLLECT(DISTINCT u.vv ORDER BY
2
DISTINCTu.vv) AS strarray),
3
',')
4FROM tmp_suu u;
试试有木有
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
还有这么个东西,挺有意思的.
试了下,确实,怎么distinct和order by还不能共存.
listagg加上distinct也能实现,成本应该差不多吧,还省掉一个udf的调用,你试试看select listagg(vv, ',') within group (order by vv)
from
(select distinct vv from tmp_suu);
复制代码另外我奇怪我怎么加cast会报错.bill@ORCL> create or replace type strarray is table of varchar2(32);
2/
类型已创建。
已用时间:00: 00: 00.01
bill@ORCL> SELECT CAST(COLLECT(vv) AS strarray)
2FROM tmp_suu;
SELECT CAST(COLLECT(vv) AS strarray)

*
第 1 行出现错误:
ORA-00932: 数据类型不一致: 应为 -, 但却获得 -

已用时间:00: 00: 00.04复制代码
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
你的tmp_suu怎么定义的?我这里没有问题:
create table tmp_suu (vv varchar2(32));
SELECT CAST(COLLECT(vv) AS strarray) from tmp_suu;
CAST(COLLECT(VV)ASSTRARRAY)
--------------------------------------------------------------------------
STRARRAY()

回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
同意三楼的 listagg加上distinct 的方法
楼主需要sql简单,就用这方法,但楼主需要考虑字符串超长后该怎么办
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
看起来DISTINCT已经做了排序,但是也不保险,万一它用的是HASH就不对了。
如果用自定义函数,把ORDER BY 放到函数里面去好了。函数里用TABLE()就可以用SQL排序。
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
想问下,为什么加上order by 就不能去除重复了呢?
——————————————————————————————
这可能是个bug
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
lastwinner 发表于 2012-12-13 01:27
同意三楼的 listagg加上distinct 的方法
楼主需要sql简单,就用这方法,但楼主需要考虑字符串超长后该怎么 ...

wmsys.wm_concat现在能返回CLOB了,但也没法将排序和DISTINCT放到一起。
回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
newkid 发表于 2012-12-13 01:53
wmsys.wm_concat现在能返回CLOB了,但也没法将排序和DISTINCT放到一起。

所以 现在决定 自己写个object
集连接、排序、distinct 于一体了 ~~~~(>_<)~~~~
因为这类需求经常是伴随着group 出现的,要求计算每个group 某列的sum 、某列的连接
所以 listagg 好像也不够强悍……

回复

使用道具 举报

千问 | 2017-1-11 08:23:59 | 显示全部楼层
newkid 发表于 2012-12-13 01:20
你的tmp_suu怎么定义的?我这里没有问题:
create table tmp_suu (vv varchar2(32));

擦,这也会出问题,我ctas了,vv成了char3,,结果就会报那错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行