MySQL一直以來都支持正則匹配,不過對于正則替換則一直到MySQL8.0才支持。對于這類場景,以前要么在MySQL端處理,要么把數(shù)據(jù)拿出來在應(yīng)用端處理。
比如我想把表y1的列str1的出現(xiàn)第3個action的子串替換成dble,怎么實現(xiàn)?
1.自己寫SQL層的存儲函數(shù)。代碼如下寫死了3個,沒有優(yōu)化,僅僅作為演示,MySQL里非常不建議寫這樣的函數(shù)。
- mysql
- DELIMITER$$
- USE`ytt`$$
- DROPFUNCTIONIFEXISTS`func_instr_simple_ytt`$$
- CREATEDEFINER=`root`@`localhost`FUNCTION`func_instr_simple_ytt`(
- f_strVARCHAR(1000),--Parameter1
- f_substrVARCHAR(100),--Parameter2
- f_replace_strvarchar(100),
- f_timesint--timescounter.onlysupport3.
- )RETURNSvarchar(1000)
- BEGIN
- declarev_resultvarchar(1000)default'ytt';--result.
- declarev_substr_lenintdefault0;--searchstringlength.
- setf_times=3;--onlysupport3.
- setv_substr_len=length(f_substr);
- selectinstr(f_str,f_substr)into@p1;--Firstrealposition.
- selectinstr(substr(f_str,@p1+v_substr_len),f_substr)into@p2;Secondaryvirtualposition.
- selectinstr(substr(f_str,@p2+@p1+2*v_substr_len-1),f_substr)into@p3;--Thirdvirtualposition.
- if@p1>0&&@p2>0&&@p3>0then--Fine.
- select
- concat(substr(f_str,1,@p1+@p2+@p3+(f_times-1)*v_substr_len-f_times)
- ,f_replace_str,
- substr(f_str,@p1+@p2+@p3+f_times*v_substr_len-2))intov_result;
- else
- setv_result=f_str;--Neverchanged.
- endif;
- --Purgeallsessionvariables.
- set@p1=null;
- set@p2=null;
- set@p3=null;
- returnv_result;
- end;
- $$
- DELIMITER;
- --調(diào)用函數(shù)來更新:
- mysql>updatey1setstr1=func_instr_simple_ytt(str1,'action','dble',3);
- QueryOK,20rowsaffected(0.12sec)
- Rowsmatched:20Changed:20Warnings:0
- 2.導(dǎo)出來用sed之類的工具替換掉在導(dǎo)入,步驟如下:(推薦使用)1)導(dǎo)出表y1的記錄。
- mysqlmysql>select*fromy1intooutfile'/var/lib/mysql-files/y1.csv';QueryOK,20rowsaffected(0.00sec)
2)用sed替換導(dǎo)出來的數(shù)據(jù)。- shellroot@ytt-Aspire-V5-471G:/var/lib/mysql-files#sed-i's/action/dble/3'y1.csv
3)再次導(dǎo)入處理好的數(shù)據(jù),完成。- mysql
- mysql>truncatey1;
- QueryOK,0rowsaffected(0.99sec)
- mysql>loaddatainfile'/var/lib/mysql-files/y1.csv'intotabley1;
- QueryOK,20rowsaffected(0.14sec)
- Records:20Deleted:0Skipped:0Warnings:0
- 以上兩種還是推薦導(dǎo)出來處理好了再重新導(dǎo)入,性能來的高些,而且還不用自己費勁寫函數(shù)代碼。那MySQL8.0對于以上的場景實現(xiàn)就非常簡單了,一個函數(shù)就搞定了。
- mysqlmysql>updatey1setstr1=regexp_replace(str1,'action','dble',1,3);QueryOK,20rowsaffected(0.13sec)Rowsmatched:20Changed:20Warnings:0
還有一個regexp_instr也非常有用,特別是這種特指出現(xiàn)第幾次的場景。比如定義SESSION變量@a。- mysqlmysql>set@a='aabbcceefilucy111bs234523556119101020301040';QueryOK,0rowsaffected(0.04sec)
拿到至少兩次的數(shù)字出現(xiàn)的第二次子串的位置。- mysqlmysql>selectregexp_instr(@a,'[:digit:]{2,}',1,2);+--------------------------------------+|regexp_instr(@a,'[:digit:]{2,}',1,2)|+--------------------------------------+|50|+--------------------------------------+1rowinset(0.00sec)
那我們在看看對多字節(jié)字符支持如何。- mysql
- mysql>set@a='中國美國俄羅斯日本中國北京上海深圳廣州北京上海武漢東莞北京青島北京';
- QueryOK,0rowsaffected(0.00sec)
- mysql>selectregexp_instr(@a,'北京',1,1);
- +-------------------------------+
- regexp_instr(@a,'北京',1,1)
- +-------------------------------+
- 17
- +-------------------------------+
- 1rowinset(0.00sec)
- mysql>selectregexp_instr(@a,'北京',1,2);
- +-------------------------------+
- regexp_instr(@a,'北京',1,2)
- +-------------------------------+
- 29
- +-------------------------------+
- 1rowinset(0.00sec)
- mysql>selectregexp_instr(@a,'北京',1,3);
- +-------------------------------+
- regexp_instr(@a,'北京',1,3)
- +-------------------------------+
- 41
- +-------------------------------+
- 1rowinset(0.00sec)
- 那總結(jié)下,這里我提到了MySQL8.0的兩個最有用的正則匹配函數(shù)regexp_replace和regexp_instr。針對以前類似的場景算是有一個完美的解決方案。