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, '高三');

數據是這個樣子的 [學校類型,年級代碼,年級名稱]

需要的結果是這樣,對gradenm列按gradeno列進行排序合併

 

4、實現

(1)wm_concat() 聚合,代碼及結果如下:

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

這個時候很明顯看到,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;

通過分析函數的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;

 

(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;

 

listagg() 可接收兩個參數,聚合列 和 分隔符,不寫分隔符參數即無分隔符直接拼接。

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

group by,分組,按組統計。有用到分組的才需要。

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

補充:wm_concat是在wmsys用戶下的一個函數,是oracle的一個非公開的函數,而且,wm_concat在前面幾個版本中的返回值數據類型也不相同,在新版本12c中更是直接被拋棄了。

所以,日常開發中並不建議使用wm_concat。強行建議使用listagg。要麼就自己寫個函數用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章