1. 程式人生 > >SQL---模糊查詢與正則表示式詳解和對比

SQL---模糊查詢與正則表示式詳解和對比

1:模糊查詢

在進行資料庫查詢的時候,有完整查詢和模糊查詢之分;

完整查詢就是我們平時查詢的普通語句(對某個查詢條件確定的前提下),而模糊查詢就是常見的where 後面增加了 like 關鍵字。

一般模糊查詢語句如下:

select 欄位 from 表 where 某欄位 like 條件

首先,為了直觀地檢視結果,我們建立一張學生資訊表:

學生資訊表

  1. % 模式:表示任意0個或者多個字元。可以匹配任意型別和長度的字元,有些情況下如果是中文,則使用兩個百分號(%%)表示,例如:

    select * from student where s_name like '趙%'; ----即查詢以‘趙’姓所有的學生的資訊
    

    因為只有一個學生姓氏為‘趙’,所以返回結果只有一條記錄:

    **返回結果:**01 號學生趙雷的資訊

  2. _ 模式:表示任意單個字元,匹配單個單一字元,它常用來限制表示式的字元長度語句:

比如找出名字中第二個字是“蘭”的學生資訊:

select * from student where s_name like '_蘭'; ----找出名字中第二個字是“蘭“

**返回結果:**06號學生吳蘭的資訊

再比如,如果我們忘記名字中的一部分,也可以用 _模式

select * from student where s_name like '王_明';
---如我們只記得姓‘王’,名字的最後一個字是‘明’,中間的部分忘記了

**返回結果:**09號學生王小明的資訊

  1. [ ] 模式:表示括號內所列字元的一個(類似正則表示式)。指定一個字元、字串或者範圍,要求所屁【誒的物件為它們中的一個。

    比如我們要找出,“張”姓,“李”姓,“周姓”,中,名字帶“梅”的學生的資訊

    select * from student where s_name like '[張李周]梅';
    

    **返回結果:**05號學生周梅的資訊

    注意這裡只需要有一個匹配就行,而不是返回“張李周梅”的結果

  2. [^ ] :表示不在括號所列之內的單個字元,取值和[ ]相同,但它要求所匹配的物件為指定字元以外的任意一個字元。

    找出不姓“張”,“李”,“周”的張梅,李梅,周梅等;即過濾掉這些資訊

select * from student where s_name like '[張李周]梅';

2 : 正則表示式

​ 之前用模糊查詢過濾一些資料條件,通過這些查詢已經能夠滿足開發中大部分的工作,但假設篩選條件更加複雜一點,如:需要從郵箱+手機號混合註冊的使用者中找出手機號碼註冊使用者,要給他們發生簡訊。此時,之前的過濾方法效用不大,但正則表示式可以滿足。

​ 正則表示式就是用來匹配文字的特殊字串,比如從文字中提取電話號碼,帶數字的使用者名稱,或者提取某個特定格式的文字。

​ 幾乎所有程式語言都支援正則表示式,因此,學習正則表示式很有必要。

下標中的正則模式可以應用於regexp操作符中

模式 描述
^ 匹配輸入字串的開始位置。如果設定了 RegExp 物件的 Multiline 屬性,^ 也匹配 ‘\n’ 或 ‘\r’ 之後的位置。
$ 匹配輸入字串的結束位置。如果設定了RegExp 物件的 Multiline 屬性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。
. 匹配除 “\n” 之外的任何單個字元。要匹配包括 ‘\n’ 在內的任何字元,請使用象 ‘[.\n]’ 的模式。
[…] 字元集合。匹配所包含的任意一個字元。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
[^…] 負值字元集合。匹配未包含的任意字元。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。
p1|p2 匹配 p1 或 p2 。例如,‘z|food’ 能匹配 “z” 或 “food”。’(z|f)ood’ 則匹配 “zood” 或 “food”。
* 匹配前面的子表示式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等價於{0,}。
+ 匹配前面的子表示式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等價於 {1,}。
{n} n 是一個非負整數。匹配確定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的兩個 o。
{n,m} m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。

同樣,為了直觀地展示結果,我們首先建立一個使用者表my_user:

在這裡插入圖片描述

接下來,通過正則表示式來匹配該表中的相關資訊。

2.1 匹配字串

​ 匹配字串是正則表示式最基礎的應用。我們先給出一個例子:我們從一個使用者表中查詢出名字中包含有100數字的使用者 。

SQL語句:

	select * from my_user where name regexp '100';

​ **返回結果:**得到ID為1 的使用者:張三100

在這裡插入圖片描述

​ 這裡也可以用上面的Like模糊查詢來實現,那為什麼還要使用正則表示式呢…??

​ 其實是這樣:如果我們需要匹配的結果不僅僅包含數字100 的使用者,而是200,300,500,只要是整百的都需要匹配,或者說,我們需要所有名字中包含數字的都需要匹配。在這樣的需求下, 使用Like模糊查詢就十分困難。但是使用正則表示式就很簡單。

SQL語句:

	select * from my_user where name regexp '.00';--匹配包含整百的名字,如100,300,500等

表示式中的 .00 表示任意字元,無論是數字還是字母都可以匹配,任意匹配。

返回結果:

在這裡插入圖片描述

如果要匹配所有名字裡麵包含數字的使用者:

SQL語句:

select * from my_user where name regexp '[0-9]';--匹配所有名字裡麵包含數字的使用者

返回結果:

在這裡插入圖片描述

2.2 使用或查詢

​ 如果正則表示式僅僅就是和Like有那麼一點兒的差別,也就不會有這麼高的地位了。下面才是顯示身手的時候。

​ 或查詢也叫OR查詢,是條件並列查詢的一種情況,類似程式語言中的if-else語句,只要有一個條件符合就會匹配。

SQL語句:

	select * from my_user where name regexp '100|500';---查詢名字中帶100或500數字的使用者資訊

返回結果:
在這裡插入圖片描述

​ 語句查詢了名字中包含了100或者500數字的使用者,就是說兩個數值只要匹配一個就可以返回資料。當然,也可以用給出多個情況,用豎線分割即可。如:100|500|410

​ 使用或查詢的情況,有點兒類似於select中使用or條件連線的情況,你可以把它們想象成併入了一個正則表示式。

2.3 匹配多個字元之一

正則表示式中的特殊的OR匹配:

SQL語句:

	select * from my_user where name regexp '[15]';---查詢名字中包含有數字1或者數字5的記錄,它是[1|5]的縮寫。

返回結果:

在這裡插入圖片描述

它與 select * from my_user where name regexp ‘1|5’; 返回的結果是一樣的。

​ 這種,使用方括號將字串括起來的寫法,無論方括號內有多少字串,其表達的含義都是匹配其中任意一個。 如果是[123456789]那麼就代表,匹配名字中包含1或2或3或4或5或6或7或8或9的任何一個記錄。

​ 當然,字串還可以查詢被否定的情況。[^12]如果在12之前加上一個^符號,那麼就代表除了1或2外的字串。

SQL語句:

	select * from my_user where name regexp '[^15]';

返回結果:

在這裡插入圖片描述

**說明:**表中張三100,雖然包含1,但是他包含了0。0不屬於1或者2,所以被匹配

2.4 匹配一個範圍

​ 看下我們上面有個集合[123456789],如果每次我們寫正則時候都這麼寫,那麼豈不是很麻煩。所以,我們可以簡化這種情況,使用一個範圍[1-9]來代替這串字串。如果是匹配所有數字,那麼就會包含0,我們可以使用[0-9]來表示。

SQL語句:

	select * from my_user where name regexp '[0-9]';

返回結果:

在這裡插入圖片描述

​ 這個表示式將會匹配出所有名字中包含數字的記錄。拆開理解就是,包含0或者1或者2…或者8或者9的記錄。

​ 而且,這裡的範圍不僅僅只能是數字,還可以是字母。比如[a-z]就是表示從字母a到字母z的所有數字,26個字母。小寫完了,還有大寫[A-Z]。那麼我們將其組合起來[0-9a-zA-Z]這個表示式就十分強大了,可以表示包含數字,小寫字母,大寫字母的所有記錄。

SQL語句:

	select * from my_user where name regexp '[0-9a-zA-Z]';

返回結果:

在這裡插入圖片描述

由於my_user表中名字沒有包含字母的,所以結果和上面[0-9]相同。

2.5 元字元

​ 之前匹配的內容都是單詞匹配。就是如果匹配到一次就顯示,匹配不到就不顯示。但是,複雜的情況有時候要求匹配不止一次。假設我需要匹配名字中包含2-3位數字的記錄。這個時候就需要使用一種特殊的元字元來修飾。

SQL語句:

	select * from my_user where name regexp '[0-9]{2,3}';

返回結果:
在這裡插入圖片描述

拿出這個特殊字串[0-9]{2,3},除去前面的[0-9]後面的{2,3}就被成為重複元字元,它的作用就是使得前面的數字重複一定的次數,前面[0-9]中出現一次,就記錄一次,因此返回的結果都是出現了3次的結果。

下面列一張元字元表:

元字元 作用
* 重複0次或者多次
+ 重複一次或者多次。相當於{1,}
重複0次或者1次
{n} 重複n次
{n,} 重複至少n次
{n,m} 重複n-m次

SQL語句:

	select * from my_user where name regexp '[0-9]*';--匹配名字包含或者不包含數字的記錄

返回結果:

在這裡插入圖片描述

SQL語句:

	select * from my_user where name regexp '[0-9]{2,3}'--匹配名字內包含2位數或者3位數的記錄

返回結果:

在這裡插入圖片描述

2.6 定位元字元

除了之前的重複元字元,正則還有一種特殊的定位元字元

下面列一張定位元字元表:

元字元 作用
^ 文字開始
$ 文字結尾
[[:<:]] 詞的開始
[[:>:]] 詞的結尾

​ 還記得之前區別LIKE和正則表示式的例子麼?LIKE是對整個字串進行匹配,而正則是匹配到就可以。

​ 如果現在我們需要在郵箱+手機號碼混合註冊的賬號中,挑選出手機號碼,那麼我們就要對賬號進行從頭到尾的匹配。

​ 比如手機號碼是11位數字,也就是說a11111111111不行,但是他又具備11個數字條件。所以我們要求從頭開始匹配到結尾,是11位數字。

​ 現在我們重新插入一條記錄,my_user表變為:

在這裡插入圖片描述

SQL語句:

 	select * from my_user where name regexp '^[a-z][0-9]{11}$';--匹配以a-z開頭,0-9出現11次的記錄

返回結果:

在這裡插入圖片描述


3:模糊查詢與正則表示式比較

​ 討論模糊查詢與正則表示式後,那麼什麼情況下使用Like,什麼情況下使用regexp呢?

​ 這裡只需要記住區分Like查詢與正則查詢的重要差別即可。

​ 兩個例子:

​ 1:之前的一條語句

	select * from my_user where name regexp '100';

返回結果:

在這裡插入圖片描述

	select * from my_user where name like '100';

​ 2.Like查詢的實現

返回結果:

在這裡插入圖片描述

可以清楚地看到兩者的區別:正則表示式返回了一條記錄,而Like查詢沒有匹配到任何記錄

結論:

Like查詢匹配整個列,如果需要匹配的字串(比如上面的100)包含在列中,那麼則無法匹配成功。而正則匹配則可以匹配列值內部的值,簡單來說就是它會從第一個字元開始往後匹配,只要匹配有一個成功那麼就會返回記錄。這是兩者重要的區別。