概述
在Oracle中,如果需要将多行数据合并为一行并使用逗号分隔,就需要用到listagg()或wmsys.wm_concat()函数来实现,例如查询每个班级下所有老师,显示一行为班级名称,老师名称以逗号分隔。
listagg
listagg()函数可以实现多列记录聚合为一条记录,需要和group by一起使用,例如查询班级名称,以及该班所有老师:
select t.classname,
listagg(t.TEACHERNAME, ',') within group(order by t.TEACHERNAME) as class_teachers
from V_TEACHER t
where t.ClassId = 'xxx'
group by t.classname
结果:
1 小二班 程老师,荆老师,李老师,李老师,秦老师,祝老师
wmsys.wm_concat
该函数返回来自同一个分组中指定字段的非NULL值的连接起来字符串,语法相对listagg更简单,如下:
select t.classname, wmsys.wm_concat(t.TEACHERNAME) as class_teachers
from V_TEACHER t
where t.ClassId = 'xxx'
group by t.classname
但是wmsys.wm_concat()函数默认不会排序,如果需要排序需要使用开窗函数over以及partition by,语句如下:
with etc as
(select t.classname,
wmsys.wm_concat(t.TEACHERNAME) over(partition by t.classname order by t.TEACHERNAME) as class_teachers
from V_TEACHER t
where t.ClassId = 'xxx')
select e.classname, max(e.class_teachers) from etc e group by e.classname
输出如下:
1 小二班 程老师,荆老师,李老师,李老师,秦老师,祝老师
如果压缩后的值太长怎么办?
比如查询学校名称,以及所有老师名称,最终要在一行显示,一个学校的教师可能有很多,这个时候如果用wmsys.wm_concat()函数会直接报错,wmsys.wm_concat() 和listagg()在函数实现字段合并的时候会有长度限制的问题,这个时候可以用XML函数解决,先转为xml,然后再转为clob类型,如下:
select t.schoolname,
XMLAGG(XMLELEMENT(E, t.TEACHERNAME || ',')).EXTRACT('//text()').getclobval() as school_teachers
from V_TEACHER t
where t.schoolId = 'xxx'
group by t.schoolname
但是最终结果文本最后多了一个逗号,需要单独处理一下,比如在代码里边将数据查询到本地缓存后,再截取掉。这样就的得到了没有字符大小限制的,可以直接拿来用的,用逗号拼接的字符串。