清洗數據需要將某個字段內以空格分隔的字符串拆分成多行單個的字符串,百度了很多種方法大概歸結起來也就這幾種方法最為有效,現在把貼出來:
第一種:
select regexp_substr('1 2 3','[^ ]+',1,level,'i') from dual
connect by level <= length('1 2 3') -length(regexp_replace('1 2 3',' ',''))+1;
效果就是這個樣子↓
效果
這種方法的核心就是regexp_substr函數,通過正則來拆分字符串,函數用法為:
regexp_substr(str,進行匹配的正則表達式,position,標志第幾個匹配組,modifier)。
該函數的一個缺點就是只能每次取一個字符串出來,這個就比較頭痛了,因為現在我要取分割后所有的字符串,所以現在就要用到connect by命令,來限制取幾個匹配組,當然我們是要全部的,所以就通過length來實時確定所取得匹配組數量。
通過這種方法就可以實現開題的需求,但在用的過程中發現一個問題,如果說我要給拆分后的字符串帶上ID的話這種方法就貌似失靈了,會無限次取,所以問題沒解決,有人知道的話麻煩可以告訴我一下。
第二種
1 create or replace function split(p_list varchar,p_sep varchar := ' ')兩個參數,一個實傳入字符串名,第二個是根據什么來分割 2 3 return type_split pipelined 4 5 IS 6 7 l_idx pls_integer; 8 9 v_list varchar2(50) := p_list; 10 11 begin 12 13 loop 14 15 l_idx :=instr(v_list,p_sep); 16 17 if l_idx = 0then 18 19 piperow(substr(v_list,1,l_idx-1)); 20 21 v_list :=substr(v_list,l_idx+length(p_sep)); 22 23 else 24 25 piperow(v_list); 26 27 exit; 28 29 end if; 30 31 end loop; 32 33 end split;
通過創建函數的方法實現拆分字符串,缺點同一,無法實現取ID
用法:
selelct * from table(split(這里寫字符串,’ ’));
與第二種異曲同工的還有接下來這一種
第二種.2
1 CREATE OR REPLACE 2 FUNCTION splitstr (str IN CLOB, 3 i IN NUMBER := 0, 4 sep IN VARCHAR2 := ',' 5 ) 6 RETURN VARCHAR2 7 /************************************** 8 52 * Name: splitstr 9 53 * Author: Sean Zhang. 10 54 * Date: 2012-09-03. 11 55 * Function: 返回字符串被指定字符分割后的指定節點字符串。 12 56 * Parameters: str: 待分割的字符串。 13 57 i: 返回第幾個節點。當i為0返回str中的所有字符,當i 超過可被分割的個數時返回空。 14 58 sep: 分隔符,默認逗號,也可以指定字符或字符串。當指定的分隔符不存在於str中時返回sep中的字符。 15 59 * Example: select splitstr('abc,def', 1) as str from dual; 得到 abc 16 60 select splitstr('abc,def', 3) as str from dual; 得到 空 17 61 **************************************/ 18 IS 19 t_i NUMBER; 20 t_count NUMBER; 21 t_str VARCHAR2 (4000); 22 BEGIN 23 IF i = 0 24 THEN 25 t_str := str; 26 ELSIF INSTR (str, sep) = 0 27 THEN 28 t_str := sep; 29 ELSE 30 SELECT COUNT ( * ) 31 INTO t_count 32 FROM table (split (str, sep)); 33 IF i <= t_count 34 THEN 35 SELECT str 36 INTO t_str 37 FROM (SELECT ROWNUM AS item, COLUMN_VALUE AS str 38 FROM table (split (str, sep))) 39 WHERE item = i; 40 END IF; 41 END IF; 42 43 RETURN t_str; 44 END;
第三種:
個人認為第三種才是最有效果的用了with as命令,以下優點解釋摘自網絡
With查詢語句不是以select開始的,而是以“WITH”關鍵字開頭 可認為在真正進行查詢之前預先構造了一個臨時表TT,之后便可多次使用它做進一步的分析和處理
WITHClause方法的優點:增加了SQL的易讀性,如果構造了多個子查詢,結構會更清晰;更重要的是:“一次分析,多次使用”,這也是為什么會提供性能的地方,達到了“少讀”的目標。
第一種使用子查詢的方法表被掃描了兩次,而使用WITH Clause方法,表僅被掃描一次。這樣可以大大的提高數據分析和查詢的效率。
另外,觀察WITH Clause方法執行計划,其中“SYS_TEMP_XXXX”便是在運行過程中構造的中間統計結果臨時表。
1 with temp0 as (select LEVEL lv from dualCONNECT BY LEVEL <= 100) 2 3 select id, 4 5 substr(t.vals,instr(t.vals, ' ', 1, tv.lv)+ 1,instr(t.vals, ' ', 1, tv.lv + 1)-(instr(t.vals, ' ', 1, tv.lv) + 1)) ASattr4 6 7 from 8 9 (select id,' ' || attr4 || ' ' ASvals,length(attr4 || ' ') - nvl(length(REPLACE(attr4, ' ')), 0) AS cnt 10 11 fromT_FLIGHT_TLX_TOTAL where rownum < 3) t 12 13 join temp0 tv on tv.lv <= t.cnt order by 1;