轉載:
https://blog.csdn.net/qq_39390545/article/details/106414765
一、MySQL通配符模糊查詢(%,_)
1-1. 通配符的分類
- "%" 百分號通配符: 表示任何字符出現任意次數 (可以是0次)
- "_" 下划線通配符:表示只能匹配單個字符,不能多也不能少,就是一個字符。當然,也可以like "陳____",數量不限
- like操作符:LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配進行比較;但如果like后面沒出現通配符,則在SQL執行優化時將 like 默認為 “=”執行
注意: 如果在使用like操作符時,后面沒有使用通用匹配符(%或_),那么效果是和“=”一致的。
1-2. 通配符的使用
1) % 通配符:
-- 模糊匹配含有“網”字的數據
SELECT * from app_info where appName like '%網%';
-- 模糊匹配以“網”字結尾的數據
SELECT * from app_info where appName like '%網';
-- 模糊匹配以“網”字開頭的數據
SELECT * from app_info where appName like '網%';
-- 精准匹配,appName like '網' 等同於:appName = '網'
SELECT * from app_info where appName = '網'; -- 等同於 SELECT * from app_info where appName like '網';
-- 模糊匹配含有“xxx網xxx車xxx”的數據,如:"途途網約車司機端、網絡約車平台"
SELECT * from app_info where appName like '%網%車%';
2) _ 通配符:
-- 查詢以“網”為結尾的,長度為三個字的數據,如:"鏈家網",
SELECT * from app_info where appName like '__網';
注意:'%__網、__%網' 等同於 '%網'
-- 查詢前三個字符為XX網,后面任意匹配,如:"城通網盤、模具網平台"
SELECT * from app_info where appName like '__網%';
-- 模糊匹配含有“xx網x車xxx”的數據,如:"攜程網約車客戶端"
SELECT * from app_info where appName like '__網_車%';
注意事項:
- 注意大小寫,在使用模糊匹配時,也就是匹配文本時,MySQL默認配置是不區分大小寫的。當你使用別人的MySQL數據庫時,要注意是否區分大小寫,是否區分大小寫取決於用戶對MySQL的配置方式.如果是區分大小寫,那么像Test12這樣記錄是不能被"test__"這樣的匹配條件匹配的
- 注意尾部空格,"%test"是不能匹配"test "這樣的記錄的
- 注意NULL,%通配符可以匹配任意字符,但是不能匹配NULL,也就是說SELECT * FROM blog where title_name like '%';是匹配不到title_name為NULL的的記錄。
1-3. 技巧與建議:
正如所見,MySQL的通配符很有用。但這種功能是有代價的:通配符搜索的處理一般要比前面討論的其他搜索所花時間更長,消耗更多的內存等資源。這里給出一些使用通配符要記住的技巧
- 不要過度使用通配符。如果其他操作符能達到相同的目的,應該使用其他操作符
- 在確實需要使用通配符時,除非絕對有必要,否則不要把它們用在搜索模式的開始處。因為MySQL在where后面的執行順序是從左往右執行的,如果把通配符置於搜索模式的開始處(最左側),搜索起來是最慢的(因為要對全庫進行掃描)。
- 仔細注意通配符的位置。如果放錯地方,可能不會返回想要的數據
有細心地朋友會發現,如果數據中有“%”、“_”等符號,那豈不是和通配符沖突了?
SELECT * from app_info where appName LIKE '%%%'; SELECT * from app_info where appName LIKE '%_%';
確實如此,上面面兩條SQL語句查詢的都是全表數據,而不是帶有"%"和"_"的指定數據。這里需要加 ESCAPE 關鍵字進行轉義。
如下,ESCAPE 后面跟着一個字符,里面寫着什么,MySQL就把那個符號當做轉義符,一般我就寫成"/";然后就像 C語言中轉義字符一樣 例如 ‘\n’,’\t’, 把這個字符寫在你需要轉義的那個%號前就可以了;
SELECT * from app_info where appName LIKE '%/_%' ESCAPE '/';
下面我們來看看MySQL的第二類模糊匹配方式 --- 內置函數查詢
二、MySQL內置函數檢索(locate,position,instr)
話接上文,通過內置函數locate,position,instr進行匹配,相當於Java中的str.contains()方法,返回的是匹配內容在字符串中的位置,效率和可用性上都優於通配符匹配。
SELECT * from app_info where INSTR(`appName`, '%') > 0; SELECT * from app_info where LOCATE('%', `appName`) > 0; SELECT * from app_info where POSITION( '%' IN `appName`) > 0;
如上,三種內置函數默認都是:> 0,所以下列 > 0 可加可不加,加上可讀性更好。
OK,下面一起來看看這三種內置函數的使用方法吧。
先明確一下,MySQL中的角標從左往右是從1開始的,不像java最左邊第一位角標是0,因此在MySQL中角標為0時說明不存在。
2-1. LOCATE()函數
語法: LOCATE(substr,str)
返回 substr 在 str 中第一次出現的位置。如果 substr 在 str 中不存在,返回值為 0,如果substr 在 str 中存在,返回值為:substr 在 str中第一次出現的位置
注意:LOCATE(substr,str)與 POSITION(substr IN str)是同義詞,功能相同。
語法: LOCATE(substr, str, [pos])
從位置pos開始的字符串str中第一次出現子字符串substr的位置。 如果substr不在str中,則返回0。 如果substr或str為NULL,則返回NULL。
SELECT locate('a', 'banana'); -- 2 SELECT locate('a', 'banana', 3); -- 4 SELECT locate('z', 'banana'); -- 0 SELECT locate(10, 'banana'); -- 0 SELECT locate(NULL , 'banana'); -- null SELECT locate('a' , NULL ); -- null
實例:
-- 用LOCATE關鍵字進行模糊匹配,等同於:"like '%網%'"
SELECT * from app_info where LOCATE('網', `appName`) > 0;
-- 用LOCATE關鍵字進行模糊匹配, 從第二個字符開始匹配"網",則"網易雲游戲、網來商家"等數據就被過濾了
SELECT * from app_info where LOCATE('網', `appName`, 2) > 0;
2-2. POSITION()方法
語法:POSITION(substr IN substr)
這個方法可以理解為locate(substr,str)方法的別名,因為它和locate(substr,str)方法的作用是一樣的。
實例:
-- 用POSITION關鍵字進行模糊匹配,等同於:"like '%網%'"
SELECT * from app_info where POSITION( '網' IN `appName`);
2-3. INSTR()方法
語法: INSTR(str,substr)
返回字符串str中第一次出現子字符串substr的位置。INSTR()與LOCATE()的雙參數形式相同,只是參數的順序相反。
實例:
-- 用INSTR關鍵字進行模糊匹配,功能跟like一樣 ,等同於:"like '%網%'"
SELECT * from app_info where INSTR(`appName`, '網');
-- instr函數作用,一般用於檢索某字符在某字符串中的位置,等同於:"like '%網%'"
SELECT * from app_info where INSTR(`appName`, '網') > 0;
三、MySQL基於regexp、rlike的正則匹配查詢
MySQL中的regexp和rlike關鍵字屬於同義詞,功能相同。本文以regexp為准。
REGEXP 不支持通配符"%、_",支持正則匹配規則,是一種更細力度且優雅的匹配方式,一起來看看吧
-- 這里給出regexp包含的參數類型
模式 | 描述 |
^ | 匹配字符串的開始位置,如“^a”表示以字母a開頭的字符串。 |
$ | 匹配字符串的結束位置,如“X$”表示以字母X結尾的字符串。 |
. | 匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用像 '[.\n]' 的模式 |
[...] | 字符集合。匹配所包含的任意一個字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 |
[^...] | 負值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p' |
p1|p2|p3 | 匹配 p1 或 p2 或 p3。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food" |
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。 |
+ ---------- ? |
匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。 -------------------------------------------------------------------------------------------- 問號匹配0次或1次 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o |
{n,} | 匹配不少於n個 |
{n,m} | m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次 |
-- REGEXP '網' 等同於 like '%網%'
SELECT * from app_info where appName REGEXP '網'; -- 等同於 SELECT * from app_info where appName like '%網%';
3-1. regexp中的 OR : |
功能:可以搜索多個字符串之一,相當於 or
-- 支持 "|" ‘或’符號,匹配包含“中國”或“互聯網”或“大學”的數據,支持疊加多個
SELECT * from app_info where appName REGEXP '中國|互聯網|大學';
-- 匹配同時命中“中國”、“網”的數據可以用".+"連接,代表中國xxxx網,中間允許有任意個字符,順序不能反。
SELECT * from app_info where appName REGEXP '中國.+網';
3-2. REGEXP中的正則匹配 : []
功能:匹配[]符號中幾個字符之一,支持解析正則表達式
-- 匹配包含英文字符的數據,默認不區分大小寫情況下
SELECT * from app_info where appName REGEXP '[a-z]';
-- 跟like一樣,取反集加 "not REGEXP" 即可,下面不再贅述
SELECT * from app_info where appName not REGEXP '[a-z]';
--區分大寫, 需要加上"BINARY"關鍵字, 如where appName REGEXP BINARY 'Hello'
SELECT * from app_info where appName REGEXP BINARY '[A-Z]';
-- 匹配包含數字的數據
SELECT * from app_info where appName REGEXP '[0-9]';
-- 匹配包含數字或英文的數據,
SELECT * from app_info where appName REGEXP '[a-z0-9]';
-- 查詢以5、6、7其中一個為開頭的數據
SELECT * from app_info where appName REGEXP '^[567]';
-- 查詢以5、6、7其中一個為結尾的數據
SELECT * from app_info where appName REGEXP '[567]$';
-- 任意字符開頭或者任意字符結尾
SELECT * from app_info where appName REGEXP '^.'; SELECT * from app_info where appName REGEXP '.$';
-- 查詢appName字節長度為10,任意內容的數據
SELECT * from app_info where appName REGEXP '^.{10}$';
-- 查詢appName字節長度為10,且都為英文的數據
SELECT * from app_info where appName REGEXP '^[a-z]{10}$';
-- 查詢appName字節長度為10,且都為大寫英文的數據,加上BINARY即可
SELECT * from app_info where appName REGEXP BINARY '^[a-z]{10}$';
-- 查詢version_name字節長度為6,且都為數字或"." 的數據
SELECT * from app_info where version_name REGEXP '^[0-9.]{6}$';
-- 查詢version_name字節長度為6,且都為數字或"." 的數據;要求首位為1
SELECT * from app_info where version_name REGEXP '^1[0-9.]{5}$';
-- 查詢version_name字節長度為6,且都為數字或"." 的數據;要求首位為1,末位為7
SELECT * from app_info where version_name REGEXP '^1[0-9.]{4}7$';
-- 查詢version_name字節長度為6位以上,且都為數字或"." 的數據;要求首位為1,末位為7
SELECT * from app_info where version_name REGEXP '^1[0-9.]{4,}7$';
-- 查詢version_name字節長度為 6 - 8 位,且都為數字或"." 的數據;要求首位為1,末位為7
SELECT * from app_info where version_name REGEXP '^1[0-9.]{4,6}7$';
-- 首位字符不是中文的
SELECT * from app_info where appName REGEXP '^[ -~]';
-- 首位字符是中文的
SELECT * from app_info where appName REGEXP '^[^ -~]';
-- 查詢不包含中文的數據
SELECT * from app_info where appName REGEXP '^([a-z]|[0-9]|[A-Z])+$';
-- 以5或F開頭的,且包含英文的數據
SELECT * from app_info where appName REGEXP BINARY '^[5F][a-zA-Z].';
特殊符號的匹配,例如.,需要加\\(注意是兩個斜杠),但是如果在[]中可以不加:
-- 匹配name中含有.的 select * from app_info where appName regexp '\\.'; -- 匹配name中含有.的 select * from app_info where appName regexp '[.]';
3-3. 字符類匹配(posix)
mysql中有一些特殊含義的符號,可以代表不同類型的匹配:
-- 匹配name中含有數字的
select * from app_info where appName regexp '[[:digit:]]';
其他的這種字符類還有:
字符類 | 作用 |
[:alnum:] | 匹配字面和數字字符。(等同於[A~Za~z0~9]) |
[:alpha:] | 匹配字母字符。(等同於[A~Za~z]) |
[:blank:] | 匹配空格或制表符(同[\\\t]) |
[:cntrl:] | 匹配控制字符(ASCII0到37和127) |
[:digit:] | 匹配十進制數字。(等同於[0-9]) |
[:graph:] | 匹配ASCII碼值范圍33~126的字符。與[:print:]相似,但不包括空格字符 |
[:print:] | 任何可打印字符 |
[:lower:] | 匹配小寫字母,等同於[a-z] |
[:upper:] | 匹配大寫字母,等同於[A-Z] |
[:space:] | 匹配空白字符(同[\\f\\n\\r\\t\\v]) |
[:xdigit:] | 匹配十六進制數字。等同於[0-9A-Fa-f] |
這種字符類需要主要的外層要加一層[]。
3-4. [:<:]和[:>:]
上面的字符類中有兩個比較特殊的,這兩個是關於位置的,[:<:]匹配詞的開始,[:>:]匹配詞的結束,它們和 ^、$ 不同。
后者是匹配整個整體的開頭和結束,而前者是匹配一個單詞的開始和結束。
-- 只能匹配整體以a開頭的,例如abcd
select * from app_info where appName regexp '^a';
-- 能匹配整體以a開頭的,也能匹配中間的單詞以a開頭,如:dance after。
select * from app_info where appName regexp '[[:<:]]a';
[[:<:]] 、 [[:>:]] 分別匹配一個單詞開頭和結尾的空的字符串,這個單詞開頭和結尾都不是包含在alnum中的字符也不能是下划線。
select "a word a" REGEXP "[[:<:]]word[[:>:]]"; -- 1(表示匹配) select "a xword a" REGEXP "[[:<:]]word[[:>:]]"; -- 0(表示不匹配) select "weeknights" REGEXP "^(wee|week)(knights|nights)$"; -- 1(表示匹配)