能够进行复杂的查询在SQL中是非常有用的。
在这篇文章中,我们将看看你如何使用Contains String 查询。
SQL模式
SQL模式对于模式匹配非常有用,而不是使用字面比较。它们的语法比RegEx更有限,但它们在各种SQL版本中更通用。
SQL模式使用LIKE 和NOT LIKE 操作符和元字符(代表自己以外的东西的字符)% 和_ 。
这些操作符是这样使用的:column_name LIKE pattern :
| 字符 | 意义 |
|---|---|
% | 任何序列的字符 |
_ | 完全是一个字符 |
你可以在各种不同的使用情况下使用这些字符,下面是一些例子:
| 示例模式 | 用途 |
|---|---|
re% | 以一个特定的子串开始的字符串 |
%re | 以某一特定子串为结尾的字符串 |
%re% | 在字符串的任何地方都有一个特定的子串的字符串 |
%re_ | 在字符串的结尾处有一个特定的子串的字符串¹ |
__re% | 在从头开始的特定位置有特定子串的字符串²。 |
¹ (在这个例子中,倒数第二和倒数第三的字符被确定)
² (在这个例子中,第三和第四的字符被确定)
查询示例
SELECT name FROM planets
WHERE name LIKE "%us";
其中planets 是一个包含太阳系行星数据的表格。
通过这个查询,你将得到以下以 "我们 "结尾的行星的名称:
| 名称 |
|---|
| 金星 |
| 天王星 |
NOT LIKE 操作符可以找到所有与模式不匹配的字符串。
让我们也在一个例子中使用它:
SELECT name FROM planets
WHERE name NOT LIKE "%u%";
通过这个查询,你可以得到所有名字中不包含字母u 的行星,如下所示:
| 名称 |
|---|
| 地球 |
| 火星 |
替代SQL中的LIKE 操作符
根据你所使用的SQL版本,你可能还可以使用SIMILAR TO 操作符。你可以使用它来补充或替代LIKE 。
SQL的SIMILAR TO 操作符
SIMILAR TO 操作符的工作方式与LIKE 操作符非常相似,包括哪些元字符可以使用。你可以对任何数量的字符使用% 操作符,而对一个字符使用_ 操作符。
让我们把用于LIKE 的例子也用在这里吧:
SELECT name FROM planets
WHERE name SIMILAR TO "%us";
你可以在使用这个运算符时在前面加上NOT ,以达到相反的效果。这就是你如何写我们之前使用的例子,用SIMILAR TO 代替:
SELECT name FROM planets
WHERE name NOT SIMILAR TO "%u%";
SQL中的RegEx
如果你需要更复杂的模式匹配呢?嗯,为此你需要使用正则表达式。
什么是RegEx?
RegEx本身就是一个强大的工具,它可以进行灵活的模式识别。你可以在许多语言中使用RegEx,如PHP、Python,还有SQL。
RegEx可以让你按字符类别(如所有字母,或只是元音,或所有数字),在替代物之间匹配模式,以及其他真正灵活的选项。你将在下面看到它们。
你可以用RegEx做什么
你可以用RegEx模式做很多不同的事情。为了看到一个很好的多样性,让我们使用一些在RegEx freeCodeCamp课程中提出的例子。
请记住,freeCodeCamp课程介绍的是JavaScript的RegEx,所以没有一个完美的匹配,我们需要转换语法。不过,它还是让你对RegEx的基本功能有了一个很好的概述,所以让我们按照这个课程,让你对RegEx的功能有一个很好的认识。
匹配字面字符串
使用RegEx最简单的方法是用它来匹配一个精确的字符序列。
例如,regex"Kevin" 将匹配所有包含这些字母的精确序列的字符串,如"Kevin"、"Kevinis great"、"this is my friendKevin"等等。
匹配具有不同可能性的字面字符串
正则表达式可以使用字符| ,来匹配不同的可能性。例如,"yes|no|maybe" 将匹配任何包含三个字符序列之一的字符串,如"也许我会做"、"美宝莲"、"独白"、"是的,我会做"、"不,我不喜欢",等等。
用通配符句子匹配任何东西
通配符句号. 匹配任何字符,例如,"hu." 将匹配任何包含h 后面是u 后面是任何字符的字符,如**"hug**"、"hum"、"hub"、"huh",也包括"husband"、"churros"、"thumb"、"shuttle"等等。
匹配单个字符的多种可能性
你可以使用一个字符类(或字符集)来匹配一组字符,例如,"b[aiu]g" 将匹配任何包含b ,然后是a 、i 和u 之间的一个字母,然后是g 的字符串,如"bug"、"big"、"bag",但也包括 "cabbage"、"ambigous"、"labbug "等等。
匹配字母表中的字母
你在上面看到了如何用字符类来匹配一组字符,但如果你想匹配一长串的字母,那就需要打很多字了。
为了避免这些打字,你可以定义一个范围。例如,你可以用"[a-e]" 匹配a 和e 之间的所有字母。
像"[a-e]at" 这样的重码可以匹配所有在a 和e 之间有一个字母的字符串,然后是a 和t ,比如**"猫**"、"蝙蝠"和**"吃**",但也包括 "鸟池"、"布卡蒂尼"、"日期",等等。
匹配数字和英文字母
你也可以用连字符来匹配数字。例如,"[0-5]" 可以匹配0 和5 之间的任何数字,包括0 和5 。
你也可以将不同的范围结合在一起,组成一个单一的字符集。例如,"[a-z0-9]" 将匹配从a 到z 的所有字母和从0 到5 的所有数字。
匹配未指定的单个字符
你也可以使用一个字符集来排除匹配中的一些字符,这些字符集被称为否定的字符集。
你可以通过在字符集的开头括号后放置一个托号字符 (^) 来创建一个否定的字符集。
例如,"[^aeiou]" 匹配所有非元音的字符。它可以匹配像 "rythm "这样的字符串,其中没有一个字符是元音,也可以匹配 "87 + 14"。
匹配出现过一次或多次的字符
如果你需要匹配一个特定的字符或一组可以出现一次或多次的字符,你可以在这个字符后面使用字符+ 。
例如,"as+i" 可以匹配包含一个a 后面有一个或多个s 后面有一个i 的字符串,如 "偶尔"、"勤奋"等等。
匹配零次或多次出现的字符
如果你可以使用+ 来匹配一个或多个字符,那么还有* 来匹配一个零次或多次的字符。
像"as*i" 这样的正则表达式可以匹配 "偶尔"和**"勤奋**"以外的字符串,如"助手"。
匹配开头的字符串模式
到目前为止,你已经看到了在字符串的任何地方进行匹配的方法,而没有说必须在哪里进行匹配的选项。
我们使用字符^ 来匹配字符串的开头,例如,像"^Ricky" 这样的重码可以匹配"Ricky 是我的朋友",但不能匹配 "这是 Ricky"。
匹配结束的字符串模式
就像有一种方法可以匹配字符串的开头,也有一种方法可以匹配字符串的结尾。
你可以使用字符$ 来匹配字符串的结尾,例如"story$" 可以匹配任何以 "story "结尾的字符串,如 "这是一个永远不会结束的故事",但不能匹配 "有时一个故事必须结束 "这样的字符串。
匹配整个字符串
你可以将两个字符^ 和$ 结合起来,来匹配整个字符串。
因此,拿前面的一个例子来说,写"b[aiu]g" ,可以同时匹配 "big "和 "bigger",但如果你只想匹配 "big"、"bag "和 "bug",加上两个开头和结尾的字符串字符,就可以确保字符串中不可能有其他字符:"^b[aiu]g$" 。这个模式将只匹配 "big"、"bag "和 "bug",它不匹配 "bigger "或 "ambiguous"。
匹配所有字母和数字
你之前已经看到了如何用一个字符类来匹配字符。
有一些预定义的类,叫做POSIX类,你可以用它们来代替。因此,如果你想匹配所有的字母和数字,比如"[0-9a-zA-Z]" ,你可以写成"[[:alphanum:]]" 。
匹配除字母和数字之外的所有内容
如果你想匹配任何不是字母或数字的东西,你可以使用alphanum POSIX类和一个否定的字符集:"[^[:alphanum:]] 。
匹配所有数字
你也可以使用一个POSIX类来匹配所有的数字,而不是使用"[0-9]" ,像这样。"[[:digit:]]".
匹配所有非数字
你可以使用digit POSIX类和一个否定的字符集来匹配任何不是数字的东西,像这样。"[^[:digit:]]".
匹配空白处
你可以用POSIX类"[[:blank:]]" 或"[[:space:]]" 匹配空白字符。这两个类的区别是:blank 只匹配空格和制表符,而space 匹配所有空白字符,包括回车、换行、换页和垂直制表符。
匹配非空格字符
你可以用"[^[:blank:]]" 匹配任何不是空格或制表符的字符。
也可以用"[^[:space:]]" 匹配任何非空格、回车、制表符、换行、空格或垂直制表符的字符。
指定匹配的上限和下限数量
你之前已经看到了如何匹配一个或多个或零个或多个字符。但有时你想匹配一定范围的模式。
为此,你可以使用数量指定器。
数量指定符是用大括号写的({ 和})。你把两个数字用逗号分开放在大括号里。第一个是模式的下限数字,第二个是模式的上限数字。
例如,如果你的模式是"Oh{2,4} yes" ,那么它将匹配 "Ohh yes "或 "Ohhh yes "这样的字符串,但不是 "Oh yes "或 "Ohhh yes"。
指定精确的匹配数量
你也可以使用除范围之外的数量指定器来指定精确的匹配数量。你可以通过在大括号内写一个数字来做到这一点。
因此,如果你的模式是"Oh{3} yes" ,那么它将只匹配 "Ohh yes"。
检查字符的混合分组
如果你想用正则表达式来检查字符组,你可以用小括号来做。
例如,你可能想同时匹配 "Penguin "和 "Pumpkin",你可以用这样的正则表达式来做:"P(engu|umpk)in" 。
RegEx模式的总结
你在这里已经看到了很多的regex选项。所以现在让我们把所有这些,以及其他一些,放到容易查阅的表格中。
RegEx模式
| 模式 | 描述 | ||
|---|---|---|---|
^ | 字符串的开头 | ||
$ | 字符串的结尾 | ||
. | 任何字符 | ||
( ) | 分组字符 | ||
[abc] | 方括号内的任何字符 | ||
[^abc] | 不在方括号内的任何字符 | ||
| `a | b | c` | a或b或c |
* | 前面元素的零个或多个 | ||
+ | 一个或多个前述元素 | ||
{n} | 前面元素的n倍 | ||
{n,m} | 前面元素的n到m倍之间 |
Posix类
在下面的表格中,你可以看到我们在上面看到的posix类,以及其他一些你可以用来创建模式的类。
| Posix类 | 类似于 | 描述 |
|---|---|---|
[:alnum:] | [a-zA-Z0-9] | A字母数字字符 |
[:alpha:] | [a-zA-Z] | 字母字符 |
[:blank:] | 空格或制表符 | |
[:cntrl:] | [^[:print:]] | 控制字符 |
[:digit:] | [0-9] | 数字字符 |
[:graph:] | [^ [:ctrl:]] | 所有具有图形表示的字符 |
[:lower:] | [a-z] | 小写字母字符 |
[:print:] | [[:graph:][:space:]] | 图形或空格字符 |
[:punct:] | 除字母和数字外的所有图形字符 | |
[:space:] | 空格、换行、制表符、回车符 | |
[:upper:] | [A-Z] | 大写字母字符 |
[:xdigit:] | [0-9a-fA-F] | 十六进制的数字 |
记住,当使用POSIX类时,你总是需要把它放在字符类的方括号内(所以你会有两对方括号)。例如,"a[[:digit:]]b" 匹配a0b,a1b ,以此类推。
如何使用RegEx模式
在这里你会看到两种操作符,REGEXP 操作符和 POSIX 操作符。请注意,你可以使用哪种操作符取决于你所使用的SQL的风格。
RegEx操作符
RegEx操作符通常不区分大小写,也就是说,它们不区分大写和小写字母。所以对它们来说,a 等于A 。但你可以改变这种默认行为,所以不要想当然。
| 操作员 | 说明 |
|---|---|
REGEXP | 如果与给定的模式相匹配,则为真 |
NOT REGEXP | 如果字符串不包含给定的模式,则为真。 |
Posix运算符
你可以使用的另一种操作符是POSIX操作符。这些操作符不是关键字,而是用标点符号表示,并且可以区分大小写,也可以不区分。
| 操作符 | 描述 |
|---|---|
~ | 大小写敏感,如果模式包含在字符串中为真 |
!~ | 大小写敏感,如果该模式不包含在字符串中,则为真。 |
~* | 不区分大小写,如果该模式包含在字符串中,则为真。 |
!~* | 不区分大小写,如果该模式不包含在字符串中,则为真。 |
RegEx和Posix示例
让我们看看如何在查询中使用这些操作符和RegEx模式。
查询示例1
对于第一个例子,你想匹配一个字符串,其中第一个字符是 "s "或 "p",第二个字符是元音。
要做到这一点,你可以使用字符类[sp] 来匹配第一个字母,你可以使用字符类[aeiou] 来匹配字符串中的第二个字母。
你还需要使用字符来匹配字符串的开始部分,即^ ,所以你要写成"^[sp][aeiou]" 。
你写出下面的查询,以得到名字符合模式的用户列表:
SELECT name FROM users
WHERE name REGEXP '^[sp][aeiou]';
而如果改变了默认的不区分大小写的行为,你就需要写一个允许大写和小写字母的模式,比如"^[spSP][aeiouAEIOU]" ,并在查询中使用它,如下图:
SELECT name FROM users
WHERE name REGEXP '^[spSP][aeiouAEIOU]';
或者使用POSIX运算符,在这种情况下,你可以使用不区分大小写的运算符,~* ,你就不需要在一个字符类里面同时写大写和小写字母。你可以把查询写成下面的样子:
SELECT name FROM users
WHERE name ~* '^[sp][aeiou]';
由于该操作符的定义是不区分大小写的,你不需要担心在字符类中同时指定大写和小写字母。
这些查询将返回一个与下面类似的结果的表格:
| 名称 |
|---|
| 塞尔吉奥 |
| PAUL |
| 萨曼莎 |
| 萨拉菲娜 |
查询实例2
作为第二个例子,假设你想找到一种十六进制的颜色。你可以使用POSIX类[:xdigit:] ,它与字符类[0-9a-fA-F] 的作用相同。
写作#[[:xdigit:]]{3} 或#[[:xdigit:]]{6} 将匹配十六进制颜色的速记或长记形式:第一个将匹配像#398 的颜色,第二个将匹配像#00F5C4 的颜色。
你可以使用字符分组和| ,将它们结合起来,形成一个单一的RegEx模式,匹配这两种颜色,并在查询中使用它,如下所示:
SELECR color FROM styles
WHERE color REGEXP '#([[:xdigit:]]{3}|[[:xdigit:]]{6})';
SELECR color FROM styles
WHERE color ~ '#([[:xdigit:]]{3}|[[:xdigit:]]{6})';
这将得到如下的结果:
| 颜色 |
|---|
#341 |
#00fa67 |
#FF00AB |
POSIX类[:xdigit:] 已经包括大写和小写字母,所以你不需要担心运算符是否区分大小写。
关于资源使用的说明
根据你的表的大小,一个包含字符串的查询可能真的是资源密集型的。当你在生产数据库中使用它们时要小心,因为你不希望你的应用程序停止工作。
结论
Contains String查询真的很有用。在这篇文章中,你已经学会了如何使用它们,而且你已经看到了一些例子。
希望你在你的武器库中增加了一个新的工具,并且你喜欢使用它!只是要注意不要让你的应用程序崩溃。