Oracle 多行数据合并为一行

2,646 阅读2分钟

概述

在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

但是最终结果文本最后多了一个逗号,需要单独处理一下,比如在代码里边将数据查询到本地缓存后,再截取掉。这样就的得到了没有字符大小限制的,可以直接拿来用的,用逗号拼接的字符串。