重写Oracle的wm_concat函数,自定义分隔符、排序
oracle中,wm_concat函數是一個聚合函數,和mysql中的group_concat函數類似,不過group_concat函數比較強大,可以定義分隔符和排序,當然所謂強大是相對的,這里假使我們不知道oracle中的over函數,也不知道listagg函數。
? ? ? ?我們先來看看wm_concat函數能實現什么功能,通俗點==>列傳行,如果不明白,請看下面截圖(可以看到分隔符默認為','順序也是雜亂的)
? ? ? ?
? ? ? ??? ? ? ?所以,接下來,我們開始重寫wm_concat函數(需要注意和需要說明的地方放在代碼注釋中...)
(1) 因為需要進行排序,首先自定義一個可變數組
| 1 2 | -- 定義可變數組,字符串類型,長度32767,存放列值 CREATE?OR?REPLACE?TYPE WYARRAY?as?TABLE?OF?VARCHAR(32767) ; |
(2)自定義排序函數、分隔符函數
| 1 2 3 4 5 6 7 8 9 10 11 12 | -- 定義分隔符函數 create?or?replace?function?delimiter(colValue??in?varchar2, ?????????????????????????????????????delimiter?in?varchar2)?return?varchar2?is ??rtnValue varchar2(32767); begin ??rtnValue := colValue ||?' delimiter=>'?|| delimiter ||?'; '; ??return?rtnValue; end?delimiter; |
| 1 2 3 4 5 6 7 8 9 10 11 12 | -- 定義排序函數 create?or?replace?function?orderby(colValue?in?varchar2, ???????????????????????????????????orderby??in?varchar2)?return?varchar2?is ??rtnValue varchar2(32767); begin ??rtnValue := colValue ||?' orderby=>'?||?LOWER(orderby) ||?'; '; ??return?rtnValue; end?orderby; |
(3) 重定義oracle接口函數、以及接口函數的實現體(實現分隔符和排序的主要代碼)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | -- 使用當前用戶權限(使用authid current_user,定義type為用戶當前用戶的權限,舉個例子:比如A用戶他可以建立表,但是A用戶在存儲過程中如果建立表可能會提示權限不夠,所以需要用authid current_user進行約束) create?or?replace?type wy_wm_concat authid?current_user?as?object ( --拼接字符串,存放中間值,當然也可以定義為clob,clob會使用臨時段,導致臨時表空間迅速增大; --查看wmsys下的function可以發(fā)現Oracle10g到oracle11g自帶的wm_concat函數的返回類型從clob變成varchar2 ??currStr VARCHAR2(32767), --分割字符串 ??delimiter VARCHAR2(64), --排序字符串(asc、desc) ??orderby VARCHAR2(64), -- 定義字符串數組 ??strArray WYARRAY, -- 初始化接口函數 ??STATIC?FUNCTION?ODCIAGGREGATEINITIALIZE(init?IN?OUT?wy_wm_concat) ????RETURN?NUMBER, -- 迭代接口函數 ??MEMBER?FUNCTION?ODCIAGGREGATEITERATE(self?????IN?OUT?wy_wm_concat, ???????????????????????????????????????colValue?IN?VARCHAR2)?RETURN?NUMBER, -- 并行時字符串合并的接口函數 ??MEMBER?FUNCTION?ODCIAGGREGATEMERGE(self?IN?OUT?wy_wm_concat, ?????????????????????????????????????next?wy_wm_concat)?RETURN?NUMBER, -- oracle終止接口函數 ??MEMBER?FUNCTION?ODCIAGGREGATETERMINATE(self????????IN?wy_wm_concat, ?????????????????????????????????????????returnValue?OUT?VARCHAR2, ?????????????????????????????????????????flags???????IN?NUMBER) ????RETURN?NUMBER ) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | create?or?replace?type body wy_wm_concat?is??--定義函數的body ??--初始化函數 ??STATIC?FUNCTION?ODCIAGGREGATEINITIALIZE(init?IN?OUT?wy_wm_concat) ????RETURN?NUMBER?is ??begin ????init := wy_wm_concat('',?',',?'asc', WYARRAY()); ????return?ODCICONST.Success; ??END; ??-- 字符串拼接,self 為當前聚集函數的指針,用來與前面的計算結果進行關聯 ??MEMBER?FUNCTION?ODCIAGGREGATEITERATE(self?????IN?OUT?wy_wm_concat, ???????????????????????????????????????colValue?IN?VARCHAR2)?RETURN?NUMBER?is ????tempStr?varchar(500); ????extendStr?varchar(500); ????deStr?varchar(100); ????deLen?int?default?0; ????segStr?varchar(500); ????--定義一個二維數組 ????TYPE varArry?IS?VARRAY(2)?OF?VARCHAR2(200); ????tempArry varArry := varArry('',?''); ??begin ????if instr(colValue,?' ', 1) > 0?then ??????tempStr := substr(colValue, 1, instr(colValue,?' ', 1) - 1); ????else ??????tempStr := colValue; ????end?if; ????--排序和分隔符 ????extendStr :=?REPLACE(colValue, tempStr ||?' '); ????if instr(extendStr,?' ', 1) > 0?then ??????tempArry(1) := substr(extendStr, 1, instr(extendStr,?' ', 1) - 1); ??????tempArry(2) := substr(extendStr, instr(extendStr,?' ', 1)); ??????for?i?in?1 .. tempArry.count?loop ????????-- 獲取分隔符 ????????if (tempArry(i)?is?not?null)?and ???????????(instr(tempArry(i),?'delimiter=>') > 0)?THEN ??????????deStr :=?'delimiter=>'; ??????????deLen := length(deStr); ??????????segStr := substr(trim(tempArry(i)), ???????????????????????????instr(trim(tempArry(i)), deStr) + deLen); ??????????self.delimiter := SUBSTR(segStr, 1, instr(segStr,?';', -1) - 1); ????????END?IF; ????????-- 獲取排序字符串 ????????if tempArry(i)?is?not?null?and ???????????(instr(tempArry(i),?'orderby=>') > 0)?THEN ??????????deStr :=?'orderby=>'; ??????????deLen := length(deStr); ??????????segStr := substr(trim(tempArry(i)), ???????????????????????????instr(trim(tempArry(i)), deStr) + deLen); ??????????self.orderby := SUBSTR(segStr, 1, instr(segStr,?';', -1) - 1); ????????END?IF; ??????end?loop; ????end?if; ????-- 存放入數組 ????self.strArray.extend; ????self.strArray(self.strArray.count) := tempStr; ????return?ODCICONST.Success; ??END; ??--并行操作是用來合并兩個聚集函數的兩個不同的指針對應的結果 ??MEMBER?FUNCTION?ODCIAGGREGATEMERGE(self?IN?OUT?wy_wm_concat, ?????????????????????????????????????next?wy_wm_concat)?RETURN?NUMBER?is ??begin ????-- 將next數組中元素全部放入self指針對應的數組中 ????for?i?in?1 ..?next.strArray.count?loop ??????self.strArray.extend; ??????self.strArray(self.strArray.count) :=?next.strArray(i); ????end?loop; ????return?ODCICONST.Success; ??END; ??-- 終止函數,返回結果 ??MEMBER?FUNCTION?ODCIAGGREGATETERMINATE(self????????IN?wy_wm_concat, ?????????????????????????????????????????returnValue?OUT?VARCHAR2, ?????????????????????????????????????????flags???????IN?NUMBER)?RETURN?NUMBER?IS ????temp_rtnValue varchar2(32767); ??BEGIN ????-- 排序 ????if INSTR(self.orderby,?'desc') > 0?THEN ??????for?x?in?(select?column_value ??????????????????from?Table(self.strArray) ?????????????????order?by?1?DESC) loop ????????temp_rtnValue := temp_rtnValue || self.delimiter || x.column_value; ??????end?loop; ????ELSE ??????for?x?in?(select?column_value?from?Table(self.strArray)?order?by?1?ASC) loop ????????temp_rtnValue := temp_rtnValue || self.delimiter || x.column_value; ??????end?loop; ????END?IF; ????returnValue := ltrim(temp_rtnValue, self.delimiter); ????return?ODCICONST.Success; ??END; END; |
(4)自定義聚集函數
| 1 2 3 | -- 定義聚集函數(未開啟并行計算功能) create?or?replace?function?wy_concat(colValue? VARCHAR2)?RETURN?VARCHAR2 ??AGGREGATE USING wy_wm_concat; |
? 至此,主要的代碼已經全部奉上,看看運行效果,如下截圖:
? ①看看調用的默認情況(分隔符默認是逗號,排序默認是升序,在初始化函數中如此定義的)
??
? ?②自定義分隔符(利用分隔符函數將分隔符定義為*)
??
? ?③降序排序
? ?
? ? ④去重,為了可以使用wm_concat自帶的去重函數,所以在自定義分隔符和排序函數時,實質是實用了字符串處理(如果你覺得處理字符串麻煩,可以自定義 type... as object ,在使用的時候可以很方便,不會用的童鞋可以私下問)
? ?
總結
以上是生活随笔為你收集整理的重写Oracle的wm_concat函数,自定义分隔符、排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS中的跨域问题
- 下一篇: 2022河北省大学排名(最新高校排行榜)