转自:https://blog.csdn.net/Huay_Li/article/details/81257655
1、操作系统 windows 10
2、数据库:Oracle Database 11g r2
还是看例子吧。。。关于wm_concat聚合无法直接排序聚合的问题和oracle 11g的新函数listagg。
-
--创建学校类型-年级表
-
create
table SchoolGrade(
-
schoolType varchar2(
20),
--学校类型
-
gradeno
number(
8),
--年级代码
-
gradenm varchar2(
20)
--年级名称
-
);
-
--插入数据
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
101,
'一年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
102,
'二年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
103,
'三年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
104,
'四年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
105,
'五年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'小学',
106,
'六年级');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'初中',
201,
'初一');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'初中',
202,
'初二');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'初中',
203,
'初三');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'高中',
301,
'高一');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'高中',
302,
'高二');
-
insert
into SchoolGrade (SCHOOLTYPE, GRADENO, GRADENM)
-
values (
'高中',
303,
'高三');
数据是这个样子的 [学校类型,年级代码,年级名称]
需要的结果是这样,对gradenm列按gradeno列进行排序合并
(1)wm_concat() 聚合,代码及结果如下:
-
select schooltype, wm_concat(gradenm) gradenm
-
from schoolgrade
-
group
by schooltype;
这个时候很明显看到,wm_concat默认是没有办法给gradenm排序的,当然你可以把from table的部分先查出进行排序,再进行wm_concat聚合,我只能告诉你这样并没有什么卵用。
而且wm_concat默认是用逗号进行字符串拼接,如果需求是别的分隔符,还得用replace去替换一下。
(2)尝试用wm_concat()over(partition by xx order by xx) 分析函数改进,代码及结果如下:
-
select schooltype, gradeno, wm_concat(gradenm)
over(
partition
by schooltype
order
by gradeno) grade
-
from schoolgrade a;
通过分析函数的patition进行分区分组,然后排序是order by gradeno,这样,嗯。。看结果。然后我们外面套上一层select 查询这个结果,按schooltype分组,取grade最长的,就可以查到想要的结果了。代码如下:
-
select schooltype,
max(grade) grade
-
from (
select schooltype, gradeno, wm_concat(gradenm)
over(
partition
by schooltype
order
by gradeno) grade
-
from schoolgrade a)
-
group
by schooltype;
(3)当然,不可能就这么结束了,今天的主角其实是listagg函数,Oracle Database 11g开始提供的一个聚合函数,配合分组实现上面的需求,代码和结果如下:
-
--listagg()within group(order by xx) oracle database 11g提供的新函数
-
select schooltype,
listagg(gradenm,
'、')
within
group(
order
by gradeno) gradenm
-
from schoolgrade
-
group
by schooltype;
listagg() 可接收两个参数,聚合列 和 分隔符,不写分隔符参数即无分隔符直接拼接。
within group(order by xx)里面的就是聚合列拼接顺序的排序,用法跟普通排序order by 一样。
group by,分组,按组统计。有用到分组的才需要。
****************************************
补充:wm_concat是在wmsys用户下的一个函数,是oracle的一个非公开的函数,而且,wm_concat在前面几个版本中的返回值数据类型也不相同,在新版本12c中更是直接被抛弃了。
所以,日常开发中并不建议使用wm_concat。强行建议使用listagg。要么就自己写个函数用。