1. 程式人生 > 實用技巧 >MySQL模糊查詢用法(正則、萬用字元、內建函式等)

MySQL模糊查詢用法(正則、萬用字元、內建函式等)

轉載:

https://blog.csdn.net/qq_39390545/article/details/106414765

一、MySQL萬用字元模糊查詢(%,_)

1-1. 萬用字元的分類

  1. "%" 百分號萬用字元: 表示任何字元出現任意次數 (可以是0次)
  2. "_" 下劃線萬用字元:表示只能匹配單個字元,不能多也不能少,就是一個字元。當然,也可以like "陳____",數量不限
  3. 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 '__網_車%';

注意事項:

  1. 注意大小寫,在使用模糊匹配時,也就是匹配文字時,MySQL預設配置是不區分大小寫的。當你使用別人的MySQL資料庫時,要注意是否區分大小寫,是否區分大小寫取決於使用者對MySQL的配置方式.如果是區分大小寫,那麼像Test12這樣記錄是不能被"test__"這樣的匹配條件匹配的
  2. 注意尾部空格,"%test"是不能匹配"test "這樣的記錄的
  3. 注意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(substrIN 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(表示匹配)