Oracle 10g數據庫內建了符合IEEE POSIX (Portable Operating System for Unix)標準的正則表達式。熟練使用正則表達式,可以寫出簡潔,強大的SQL語句。
ORACLE中的支持正則表達式的函數主要有下面四個:
1,REGEXP_LIKE :與LIKE的功能相似
2,REGEXP_INSTR :與INSTR的功能相似
3,REGEXP_SUBSTR :與SUBSTR的功能相似
4,REGEXP_REPLACE :與REPLACE的功能相似
這四個函數在用法上與Oracle SQL 函數LIKE、INSTR、SUBSTR 和REPLACE 用法相同,但是它們使用POSIX 正則表達式代替了老的百分號(%)和通配符(_)字符。
POSIX 正則表達式由標準的元字符(metacharacters)所構成:
'^' 匹配輸入字符串的開始位置,在方括號表達式中使用,此時它表示不接受該字符集合。
'$' 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'. '.' 匹配除換行符之外的任何單字符。
'?' 匹配前面的子表達式零次或一次。
'+' 匹配前面的子表達式一次或多次。
'*' 匹配前面的子表達式零次或多次。
'|' 指明兩項之間的一個選擇。例子'^([a-z]+|[0-9]+)$'表示所有小寫字母或數字組合成的字符串。
'( )' 標記一個子表達式的開始和結束位置。
'[]' 標記一箇中括號表達式。
'{m,n}' 一個精確地出現次數範圍,m=<出現次數<=n,'{m}'表示出現m次,'{m,}'表示至少出現m次。
\num 匹配 num,其中 num 是一個正整數。對所獲取的匹配的引用。
字符簇:
[[:alpha:]] 任何字母。
[[:digit:]] 任何數字。
[[:alnum:]] 任何字母和數字。
[[:space:]] 任何白字符。
[[:upper:]] 任何大寫字母。
[[:lower:]] 任何小寫字母。
[[:punct:]] 任何標點符號。
[[:xdigit:]] 任何16進制的數字,相當於[0-9a-fA-F].
各種操作符的運算優先級
\轉義符
(), (?:), (?=), [] 圓括號和方括號
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, anymetacharacter 位置和順序。
下面收集了幾個大家在Oracle SQL中常用到的正則表達式以及它們的用法,歡迎大家補充。
1. 判斷字符串是否是數字
正則表達式:^(\-)?\d*(\.\d+)?$
用法:
select case when REGEXP_LIKE (cx.COMP_DATA_VALUE ,'^(\-)?\d*(\.\d+)?$')
then to_number(cx.COMP_DATA_VALUE)
else null
end
from change_on_setup.COMP_EXT cx
where cx.COMP_PLAN_ID = cp.COMP_PLAN_ID
and cx.COMP_ENTRY_ID = ce.COMP_ENTRY_ID
and cx.COMP_DATA_KEY = 'BUDGETSAL_A_D'
2. 判斷字符串是否是日期
判斷格式為mm/dd/yyyy的日期
正則表達式:^(((0?[1-9]|1[012])/(0?[1-9]|1\d|2[0-8])|(0?[13456789]|1[012])
/(29|30)|(0?[13578]|1[02])/31)/(19|[2-9]\d)\d{2}|0?2/29/((19|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[3579][26])00)))$
判斷格式為dd/mm/yyyy的日期
正則表達式:^(((0?[1-9]|[012]\d|3[01])\/(0?[13578]|1[02])\/((19|[2-9]\d)
\d{2}))|((0?[1-9]|[12]\d|30)\/(0?[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0?[1-9]|1\d|2[0-8])\/0?2\/((19|[2-9]\d)\d{2}))|(29\/0?2\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$
用法:
select case when REGEXP_LIKE(ui.USERS_VALUE,
'^(((0?[1-9]|[012]\d|3[01])\/(0?[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0?[1-9]|[12]\d|30)\/(0?[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0?[1-9]|1\d|2[0-8])\/0?2\/((19|[2-9]\d)\d{2}))|(29\/0?2\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$')
then to_char(to_date(ui.USERS_VALUE, 'dd/mm/yyyy'), 'dd/mm/yyyy')
when REGEXP_LIKE(ui.USERS_VALUE,
'^(((0?[1-9]|1[012])/(0?[1-9]|1\d|2[0-8])|(0?[13456789]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(19|[2-9]\d)\d{2}|0?2/29/((19|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[3579][26])00)))$')
then to_char(to_date(ui.USERS_VALUE, 'mm/dd/yyyy'), 'dd/mm/yyyy')
else null
end
from change_on_setup.USERS_INFO ui
where ui.USERS_SYS_ID = u.USERS_SYS_ID
and upper(ui.USERS_KEY) = 'REVIEW_FREQ'
3.去掉字符串中的除字母數字以外的任何字符
正則表達式:[^[:alnum:]]
用法:
下面的query將非英文字符的人名(比如Şağanaç, Çiçek)轉換成英文人名(Saganac, Cicek)。其中用到了這個正則表達式去除轉換後產生的特殊字符。
select upper(decode(instr(convert (replace(u.USERS_SYS_LASTNAME, '?'), 'us7ascii'), '?')
, 0, trim(regexp_replace(convert (u.USERS_SYS_LASTNAME, 'us7ascii'), '[^[:alnum:]]'))
, u.USERS_SYS_LASTNAME
)
|| ', ' ||
decode(instr(convert (replace(u.USERS_SYS_FIRSTNAME, '?'), 'us7ascii'), '?')
, 0, trim(regexp_replace(convert (u.USERS_SYS_FIRSTNAME, 'us7ascii'), '[^[:alnum:]]'))
, u.USERS_SYS_FIRSTNAME
)
) as "Name"
from change_on_setup.USERS_SYSINFO u
另一種轉換方法:
select regexp_replace (convert (users_sys_firstname||', '||users_sys_lastname, 'us7ascii'), '[[:punct:]]') as "Name"
from change_on_setup.USERS_SYSINFO u
4. 將字符串拆分
正則表達式:
[^,]+
[^,]*
用法:
select TRIM(REGEXP_SUBSTR('cgrant,mhoff,vstokes','[^,]+', 1,level)) POS_CODE
from dual
connect by level <= length(REGEXP_REPLACE('cgrant,mhoff,vstokes','[^,]*'))+1
輸出結果:
USERNAME
--------
cgrant
mhoff
vstokes