Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数

转自:https://blog.csdn.net/Huay_Li/article/details/81257655

1、环境:

1、操作系统 windows 10

2、数据库:Oracle Database 11g r2

 

2、需求:

还是看例子吧。。。关于wm_concat聚合无法直接排序聚合的问题和oracle 11g的新函数listagg。

 

3、准备数据:


   
   
   
   
  1. --创建学校类型-年级表
  2. create table SchoolGrade(
  3. schoolType varchar2( 20), --学校类型
  4. gradeno number( 8), --年级代码
  5. gradenm varchar2( 20) --年级名称
  6. );
  7. --插入数据
  8. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  9. values ( '小学', 101, '一年级');
  10. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  11. values ( '小学', 102, '二年级');
  12. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  13. values ( '小学', 103, '三年级');
  14. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  15. values ( '小学', 104, '四年级');
  16. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  17. values ( '小学', 105, '五年级');
  18. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  19. values ( '小学', 106, '六年级');
  20. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  21. values ( '初中', 201, '初一');
  22. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  23. values ( '初中', 202, '初二');
  24. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  25. values ( '初中', 203, '初三');
  26. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  27. values ( '高中', 301, '高一');
  28. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  29. values ( '高中', 302, '高二');
  30. insert into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
  31. values ( '高中', 303, '高三');

数据是这个样子的 [学校类型,年级代码,年级名称]

Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数_第1张图片

需要的结果是这样,对gradenm列按gradeno列进行排序合并

 

4、实现

(1)wm_concat() 聚合,代码及结果如下:


   
   
   
   
  1. select schooltype, wm_concat(gradenm) gradenm
  2. from schoolgrade
  3. group by schooltype;

Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数_第2张图片

这个时候很明显看到,wm_concat默认是没有办法给gradenm排序的,当然你可以把from table的部分先查出进行排序,再进行wm_concat聚合,我只能告诉你这样并没有什么卵用。

而且wm_concat默认是用逗号进行字符串拼接,如果需求是别的分隔符,还得用replace去替换一下。

 

(2)尝试用wm_concat()over(partition by xx order by xx) 分析函数改进,代码及结果如下:


   
   
   
   
  1. select schooltype, gradeno, wm_concat(gradenm) over( partition by schooltype order by gradeno) grade
  2. from schoolgrade a;

Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数_第3张图片

通过分析函数的patition进行分区分组,然后排序是order by gradeno,这样,嗯。。看结果。然后我们外面套上一层select 查询这个结果,按schooltype分组,取grade最长的,就可以查到想要的结果了。代码如下:


   
   
   
   
  1. select schooltype, max(grade) grade
  2. from ( select schooltype, gradeno, wm_concat(gradenm) over( partition by schooltype order by gradeno) grade
  3. from schoolgrade a)
  4. group by schooltype;

Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数_第4张图片

 

(3)当然,不可能就这么结束了,今天的主角其实是listagg函数,Oracle Database 11g开始提供的一个聚合函数,配合分组实现上面的需求,代码和结果如下:


   
   
   
   
  1. --listagg()within group(order by xx) oracle database 11g提供的新函数
  2. select schooltype, listagg(gradenm, '、') within group( order by gradeno) gradenm
  3. from schoolgrade
  4. group by schooltype;

Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数_第5张图片

 

listagg() 可接收两个参数,聚合列 和 分隔符,不写分隔符参数即无分隔符直接拼接。

within group(order by xx)里面的就是聚合列拼接顺序的排序,用法跟普通排序order by 一样。

group by,分组,按组统计。有用到分组的才需要。

****************************************

补充:wm_concat是在wmsys用户下的一个函数,是oracle的一个非公开的函数,而且,wm_concat在前面几个版本中的返回值数据类型也不相同,在新版本12c中更是直接被抛弃了。

所以,日常开发中并不建议使用wm_concat。强行建议使用listagg。要么就自己写个函数用。

你可能感兴趣的:(ORACLE)