重写Oracle的wm_concat函数,自定义分隔符、排序
oracle中,wm_concat函數(shù)是一個聚合函數(shù),和mysql中的group_concat函數(shù)類似,不過group_concat函數(shù)比較強大,可以定義分隔符和排序,當(dāng)然所謂強大是相對的,這里假使我們不知道oracle中的over函數(shù),也不知道listagg函數(shù)。
? ? ? ?我們先來看看wm_concat函數(shù)能實現(xiàn)什么功能,通俗點==>列傳行,如果不明白,請看下面截圖(可以看到分隔符默認(rèn)為','順序也是雜亂的)
? ? ? ?
? ? ? ??? ? ? ?所以,接下來,我們開始重寫wm_concat函數(shù)(需要注意和需要說明的地方放在代碼注釋中...)
(1) 因為需要進(jìn)行排序,首先自定義一個可變數(shù)組
| 1 2 | -- 定義可變數(shù)組,字符串類型,長度32767,存放列值 CREATE?OR?REPLACE?TYPE WYARRAY?as?TABLE?OF?VARCHAR(32767) ; |
(2)自定義排序函數(shù)、分隔符函數(shù)
| 1 2 3 4 5 6 7 8 9 10 11 12 | -- 定義分隔符函數(shù) 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 | -- 定義排序函數(shù) 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接口函數(shù)、以及接口函數(shù)的實現(xiàn)體(實現(xiàn)分隔符和排序的主要代碼)
| 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 | -- 使用當(dāng)前用戶權(quán)限(使用authid current_user,定義type為用戶當(dāng)前用戶的權(quán)限,舉個例子:比如A用戶他可以建立表,但是A用戶在存儲過程中如果建立表可能會提示權(quán)限不夠,所以需要用authid current_user進(jìn)行約束) create?or?replace?type wy_wm_concat authid?current_user?as?object ( --拼接字符串,存放中間值,當(dāng)然也可以定義為clob,clob會使用臨時段,導(dǎo)致臨時表空間迅速增大; --查看wmsys下的function可以發(fā)現(xiàn)Oracle10g到oracle11g自帶的wm_concat函數(shù)的返回類型從clob變成varchar2 ??currStr VARCHAR2(32767), --分割字符串 ??delimiter VARCHAR2(64), --排序字符串(asc、desc) ??orderby VARCHAR2(64), -- 定義字符串?dāng)?shù)組 ??strArray WYARRAY, -- 初始化接口函數(shù) ??STATIC?FUNCTION?ODCIAGGREGATEINITIALIZE(init?IN?OUT?wy_wm_concat) ????RETURN?NUMBER, -- 迭代接口函數(shù) ??MEMBER?FUNCTION?ODCIAGGREGATEITERATE(self?????IN?OUT?wy_wm_concat, ???????????????????????????????????????colValue?IN?VARCHAR2)?RETURN?NUMBER, -- 并行時字符串合并的接口函數(shù) ??MEMBER?FUNCTION?ODCIAGGREGATEMERGE(self?IN?OUT?wy_wm_concat, ?????????????????????????????????????next?wy_wm_concat)?RETURN?NUMBER, -- oracle終止接口函數(shù) ??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??--定義函數(shù)的body ??--初始化函數(shù) ??STATIC?FUNCTION?ODCIAGGREGATEINITIALIZE(init?IN?OUT?wy_wm_concat) ????RETURN?NUMBER?is ??begin ????init := wy_wm_concat('',?',',?'asc', WYARRAY()); ????return?ODCICONST.Success; ??END; ??-- 字符串拼接,self 為當(dāng)前聚集函數(shù)的指針,用來與前面的計算結(jié)果進(jìn)行關(guān)聯(lián) ??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); ????--定義一個二維數(shù)組 ????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; ????-- 存放入數(shù)組 ????self.strArray.extend; ????self.strArray(self.strArray.count) := tempStr; ????return?ODCICONST.Success; ??END; ??--并行操作是用來合并兩個聚集函數(shù)的兩個不同的指針對應(yīng)的結(jié)果 ??MEMBER?FUNCTION?ODCIAGGREGATEMERGE(self?IN?OUT?wy_wm_concat, ?????????????????????????????????????next?wy_wm_concat)?RETURN?NUMBER?is ??begin ????-- 將next數(shù)組中元素全部放入self指針對應(yīng)的數(shù)組中 ????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; ??-- 終止函數(shù),返回結(jié)果 ??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)自定義聚集函數(shù)
| 1 2 3 | -- 定義聚集函數(shù)(未開啟并行計算功能) create?or?replace?function?wy_concat(colValue? VARCHAR2)?RETURN?VARCHAR2 ??AGGREGATE USING wy_wm_concat; |
? 至此,主要的代碼已經(jīng)全部奉上,看看運行效果,如下截圖:
? ①看看調(diào)用的默認(rèn)情況(分隔符默認(rèn)是逗號,排序默認(rèn)是升序,在初始化函數(shù)中如此定義的)
??
? ?②自定義分隔符(利用分隔符函數(shù)將分隔符定義為*)
??
? ?③降序排序
? ?
? ? ④去重,為了可以使用wm_concat自帶的去重函數(shù),所以在自定義分隔符和排序函數(shù)時,實質(zhì)是實用了字符串處理(如果你覺得處理字符串麻煩,可以自定義 type... as object ,在使用的時候可以很方便,不會用的童鞋可以私下問)
? ?
總結(jié)
以上是生活随笔為你收集整理的重写Oracle的wm_concat函数,自定义分隔符、排序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS中的跨域问题
- 下一篇: oracle 删除字段中空格