最近項目中有不少須要作批量操做的需求,客戶端把一組逗號分隔的ID字符串傳給數據庫,存儲過程就須要把它們分割,而後逐個處理。數據庫
以往的處理方式有以下幾種:oracle
一、在存儲過程內寫循環,逐個分析字符串中的ID,而後逐個處理。缺點:循環一次處理一個,若是每次判斷都不少,效率將很受影響。適合每次處理要作單獨判斷的狀況。函數
二、使用臨時表,先調用一個存儲過程將ID拆分並插入到臨時表中,而後結合臨時表能夠寫SQL一次處理多筆。缺點:須要插臨時表,效率不高,數據量越大影響越嚴重。spa
之前的項目用的最多的仍是第2中方式,畢竟方便,且效率比第1種好。 字符串
如今項目中用到了不少不少的批量操做,不少的重複代碼讓我不厭其煩。突然想到,.Net和JS中都有split相似的函數,拆分字符串很方便,oracle中要是也有這樣的功能該多好呀。it
多方查找資料發現,給oracle添加split函數是徹底能夠實現的,避免了插入臨時表,因此效率比上面的第2中方法效率高不少。io
後來我還添加了splitstr函數,能夠很方便獲取字符串中的指定節點。 table
有了這兩個函數,處理批量操做,真是如虎添翼,效率倍增,嘿嘿……效率
好了,閒話少說,上代碼!若有不妥之處,請各位前輩博友斧正。select
1 /*
2 * Oracle 建立 split 和 splitstr 函數
3 */
4
5 /* 建立一個表類型 */
6 create or replace type tabletype as table of VARCHAR2( 32676)
7 /
8
9 /* 建立 split 函數 */
10 CREATE OR REPLACE FUNCTION split (p_list CLOB, p_sep VARCHAR2 : = ' , ')
11 RETURN tabletype
12 PIPELINED
13 /* *************************************
14 * Name: split
15 * Author: Sean Zhang.
16 * Date: 2012-09-03.
17 * Function: 返回字符串被指定字符分割後的表類型。
18 * Parameters: p_list: 待分割的字符串。
19 p_sep: 分隔符,默認逗號,也能夠指定字符或字符串。
20 * Example: SELECT *
21 FROM users
22 WHERE u_id IN (SELECT COLUMN_VALUE
23 FROM table (split ('1,2')))
24 返回u_id爲1和2的兩行數據。
25 ************************************* */
26 IS
27 l_idx PLS_INTEGER;
28 v_list VARCHAR2 ( 32676) : = p_list;
29 BEGIN
30 LOOP
31 l_idx : = INSTR (v_list, p_sep);
32
33 IF l_idx > 0
34 THEN
35 PIPE ROW (SUBSTR (v_list, 1, l_idx - 1));
36 v_list : = SUBSTR (v_list, l_idx + LENGTH (p_sep));
37 ELSE
38 PIPE ROW (v_list);
39 EXIT;
40 END IF;
41 END LOOP;
42 END;
43 /
44
45 /* 建立 splitstr 函數 */
46 CREATE OR REPLACE FUNCTION splitstr ( str IN CLOB,
47 i IN NUMBER : = 0,
48 sep IN VARCHAR2 : = ' , '
49 )
50 RETURN VARCHAR2
51 /* *************************************
52 * Name: splitstr
53 * Author: Sean Zhang.
54 * Date: 2012-09-03.
55 * Function: 返回字符串被指定字符分割後的指定節點字符串。
56 * Parameters: str: 待分割的字符串。
57 i: 返回第幾個節點。當i爲0返回str中的全部字符,當i 超過可被分割的個數時返回空。
58 sep: 分隔符,默認逗號,也能夠指定字符或字符串。當指定的分隔符不存在於str中時返回sep中的字符。
59 * Example: select splitstr('abc,def', 1) as str from dual; 獲得 abc
60 select splitstr('abc,def', 3) as str from dual; 獲得 空
61 ************************************* */
62 IS
63 t_i NUMBER;
64 t_count NUMBER;
65 t_str VARCHAR2 ( 4000);
66 BEGIN
67 IF i = 0
68 THEN
69 t_str : = str;
70 ELSIF INSTR ( str, sep) = 0
71 THEN
72 t_str : = sep;
73 ELSE
74 SELECT COUNT ( * )
75 INTO t_count
76 FROM table (split ( str, sep));
77
78 IF i <= t_count
79 THEN
80 SELECT str
81 INTO t_str
82 FROM ( SELECT ROWNUM AS item, COLUMN_VALUE AS str
83 FROM table (split ( str, sep)))
84 WHERE item = i;
85 END IF;
86 END IF;
87
88 RETURN t_str;
89 END;
90 /