REGEXP在mysql是用来执行正则表达式的一个函数
总括:
.单个字符
*,%多个字符
[]相应模糊匹配的选择范围-------^[1-5]--开始1到5任意一个
^开始
$结束
| 或者
{n}、{m,n} {n}或{m,n}符号提供了编写正则表达式的更通用方式,能够匹配模式的多少位前述原子(或“部分”)
a? 匹配0个或1个a字符 可被写为a{0,1}
a* 匹配0或多个a字符的任何序列 可被写为a{0,}
-范围
[^a-dX] 不以什么开头 不以a-d或x开头
(^|,) 用()标识模糊的作用范围
[[:<:]], [[:>:]] 文本空格等自有的边界字符
[:character_class:] 完全匹配里面的
[[=a=]] 任意匹配 等同于[a(+)],[a+],[a{1,}]
这种正则匹配就是类似遍历list看是否包含
SELECT * FROM tbl_user WHERE MACHINE_KEY_LIST regexp '836844509b4424bc6cd756749e524f8e|5fe3780850f11e7df46d9f69b35c88d6'
可以在sql中写这种sql,也可用mapper查询,在CrmCrmAccountExample中自定义(相当于写sql)
public Criteria andMachineKeyRegexp(String value) {
addCriterion("machine_key regexp", value, "machineKey");
return (Criteria) this;
}
CrmCrmAccountExample crmCrmAccountExample = new CrmCrmAccountExample();
crmCrmAccountExample.or().andMachineKeyRegexp("836844509b4424bc6cd756749e524f8e|5fe3780850f11e7df46d9f69b35c88d6");
//传入机器码被占用情况
List<CrmCrmAccount> userMachine =userRepository.selectByExample(crmCrmAccountExample);
select 'true' as QUERYID, account_id, account_name, account_status, account_type, trial_days, trial_start_time, frist_buying_time, payment_time, due_time, contacts_id, create_time, create_user_id, update_time, update_user_id, batch_id, password, status, isenuser, extract_num, export_num, wechat_name, member_id, is_primary_contact, machine_num, machine_key from 72crm_crm_account WHERE ( machine_key regexp ? )
==> Parameters: 836844509b4424bc6cd756749e524f8e|5fe3780850f11e7df46d9f69b35c88d6(String)
<== Total: 1
mapper和tk的通用mapper却别
都是单体查询
mapper可以增加Criteria实现自定义sql,通用mapper就需要在xml中写自定义的sql
示例:
像php中的preg之类的函数了,regexp正则函数如果只是简单的查询使用like即可,但复杂的还是需要使用regexp了,下面我们来看看。
MySql用户手册建议,在构造简单查询时,仍使用通配符。
如:Select [*|fieldname list] From [tablename] where [fieldname] like ["%someletter"|"%someletter%","_","?someletter"];
但在一些特殊查询中,不用正则表达式是不行的。MYSQL提供的正则表达式WHERE谓词有三个,分别是:
REGEXP, RLIKE, NOT RLIKE
用这三个替换原有的LIKE谓词,后面即可以跟正则表达式。
例如要查询字段中含有“_”的数据,则要用以下查询语句:
SELECT * FROM TABLENAME WHERE FIELDNAME RLIKE '.[_].';
扩展正则表达式的一些字符是:
· ‘.’匹配任何单个的字符。
· 字符类“[...]”匹配在方括号内的任何字符。例如,“[abc]”匹配“a”、“b”或“c”。为了命名字符的范围,使用一个“-”。“[a-z]”匹配任何字母,而“[0-9]”匹配任何数字。
· “ * ”匹配零个或多个在它前面的字符。
例如,“x*”匹配任何数量的“x”字符,“[0-9]*”匹配任何数量的数字,而“.*”匹配任何数量的任何字符。
如果REGEXP模式与被测试值的任何地方匹配,模式就匹配(这不同于LIKE模式匹配,只有与整个值匹配,模式才匹配)。
为了定位一个模式以便它必须匹配被测试值的开始或结尾,在模式开始处使用“^”或在模式的结尾用“$”。
为了找出以“b”开头的名字,使用“^”匹配名字的开始:
使用正则
SELECT * FROM pet WHERE name REGEXP BINARY ‘^b’;
SELECT * FROM pet WHERE name REGEXP ‘fy$’;
SELECT * FROM pet WHERE name REGEXP ‘w’;
SELECT * FROM pet WHERE name REGEXP ‘^…..$’;
SELECT * FROM pet WHERE name REGEXP ‘^.{5}$’;
今天在应用中遇到了这样的一个问题,
有一个字段 t1,其中的值类似于:1,1,1,2,3,3,4,4,5,5,2,4,3,2,1,2
需要从里面搜索出比如说:第一个逗号前的数字范围为3-5之间,第三个逗号前的数字的范围为3-5之间,第10个逗号前的数字范围为3-5之间,其余的都为1-5之间。。。
则sql语句可以这么写:
SELECT * FROM tb WHERE t1 REGEXP '^[3-5],[1-5],[3-5],[1-5],[1-5],[1-5],[1-5],[1-5],[1-5],[3-5],[1-5],[1-5],[1-5],[1-5],[1-5],[1-5]%';
1. 使用LIKE和NOT LIKE比较操作符(注意不能使用=或!=);
2. 模式默认是忽略大小写的;
3. 允许使用”_”匹配任何单个字符,”%”匹配任意数目字符(包括零字符);
项目中实战:
附一些mysql正则规则
^ 匹配字符串的开始部分
$ 匹配字符串的结束部分
. 匹配任何字符(包括回车和新行)
a* 匹配0或多个a字符的任何序列
a+ 匹配1个或多个a字符的任何序列
a? 匹配0个或1个a字符
de|abc 匹配序列de或abc
(abc)* 匹配序列adc的0个或者多个实例
{n}、{m,n} {n}或{m,n}符号提供了编写正则表达式的更通用方式,能够匹配模式的很多前述原子(或“部分”)。m和n均为整数。
a* 可被写为a{0,}
a+ 可被写为a{1,}
a? 可被写为a{0,1}
[a-dX] 匹配任何是a,b,c,d或者X的字符,两个其他字符之间的’-'字符构成一个范围
[^a-dX] 匹配任何不是a,b,c,d或者X的字符,前面的字符’^'是否定的意思
[.characters.] 在括号表达式中(使用[和]),匹配用于校对元素的字符序列,字符为单个字符或新行等字符名
mysql> SELECT ‘~’ REGEXP ‘[[.~.]]’; -> 1
mysql> SELECT ‘~’ REGEXP ‘[[.tilde.]]’; -> 1
[=character_class=]
在括号表达式中(使用[和]),[=character_class=]表示等同类。它与具有相同校对值的所有字符匹配,包括它本身,
[[=a=]] 等同于[a(+)],[a+],[a{1,}]
[:character_class:]
在括号表达式中(使用[和]),[:character_class:]表示与术语类的所有字符匹配的字符类。
标准的类名称是:
alnum 文字数字字符
alpha 文字字符
blank 空白字符
cntrl 控制字符
digit 数字字符
graph 图形字符
lower 小写文字字符
print 图形或空格字符
punct 标点字符
space 空格、制表符、新行、和回车
upper 大写文字字符
xdigit 十六进制数字字符
[[:<:]], [[:>:]]
这些标记表示word边界。它们分别与word的开始和结束匹配。word是一系列字字符,其前面和后面均没有字字符。字符是alnum类中的字母数字字符或下划线(_)。
mysql> select ‘fang shan zi’ regexp ‘[[:<:]]shan[[:>:]]’; -> 1
mysql> select ‘fang shan zi’ regexp ‘[[:<:]]fang[[:>:]]’; -> 1
mysql> select ‘fang shans zi’ regexp ‘[[:<:]]shan[[:>:]]’; -> 0
正则表达式使用特殊字符,应在其前面加上2个反斜杠’'字符
mysql> SELECT ’1+2′ REGEXP ’1+2′; -> 0
mysql> SELECT ’1+2′ REGEXP ’1+2′; -> 0
mysql> SELECT ’1+2′ REGEXP ’1\+2′; -> 1
样例:
由于某些原因,有时候我们没有按照范式的设计准则而把一些属性放到同一个字符串字段中。比如个人兴趣,有时候我们设计表为
create table members (uid int primary key,uname varchar(20),hobby varchar(100));
表中内容如下
mysql> select * from members;
+-----+-------+---------------------------------+
| uid | uname | hobby |
+-----+-------+---------------------------------+
| 1 | AAAA | 音乐,电影,网络,篮球,阅读,乒乓球 |
| 2 | BBBB | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
| 3 | CCCC | 交友,乒乓球 |
| 4 | DDDD | 台球,网络,看书,旅游 |
| 5 | EEEE | 音乐,发呆,下围棋,参禅 |
+-----+-------+---------------------------------+
4 rows in set (0.00 sec)
如果我们现在想查找一个与某个用户X (阅读,交友,围棋,足球,滑雪)有着相同爱好的会员记录 如果来操作呢?
在其它数据库中,我们能只通过程序来或者存储过程来分解这个 "阅读,交友,围棋,足球,滑雪" 字符串为单独的爱好项目,然后一个一个进行 like '%xxxx%' 来查询。 但在MySQL中我们可以直接利用这个regexp正规表达式 来构造SQL语句来实现。
首先我们把 '阅读,交友,围棋,足球,滑雪' 转换成为正则式 为 '阅读|交友|围棋|足球|滑雪' , | 在正则表达式中为 '或' 的意思
mysql> select replace('阅读,交友,围棋,足球,滑雪',',','|');
+---------------------------------------------+
| replace('阅读,交友,围棋,足球,滑雪',',','|') |
+---------------------------------------------+
| 阅读|交友|围棋|足球|滑雪 |
+---------------------------------------------+
1 row in set (0.00 sec)
这样我们可以用SQL语句如下。
mysql> select * from members where hobby regexp replace('阅读,交友,围棋,足球,滑雪',',','|');
+-----+-------+---------------------------------+
| uid | uname | hobby |
+-----+-------+---------------------------------+
| 1 | AAAA | 音乐,电影,网络,篮球,阅读,乒乓球 |
| 2 | BBBB | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
| 3 | CCCC | 交友,乒乓球 |
| 5 | EEEE | 音乐,发呆,下围棋,参禅 |
+-----+-------+---------------------------------+
3 rows in set (0.00 sec)
如上语句我们可以通过一句SQL得到所有hobby包含 '阅读,交友,围棋,足球,滑雪' 任一项的记录。
但上述的语句中还有一点小的缺陷,那就是把 '下围棋' 这一条也选择了出来,如果精确匹配的话这条记录不应该被选中。为了避免这种情况,我们对SQL语句做如下改进。
把正则式改为 ',(阅读|交友|围棋|足球|滑雪),' 也就是要求匹配项前后必须有一个界定符","
mysql> select concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),');
+---------------------------------------------------------------+
| concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),') |
+---------------------------------------------------------------+
| ,(阅读|交友|围棋|足球|滑雪), |
+---------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from members
-> where concat(',',hobby,',') regexp
-> concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),');
+-----+-------+---------------------------------+
| uid | uname | hobby |
+-----+-------+---------------------------------+
| 1 | AAAA | 音乐,电影,网络,篮球,阅读,乒乓球 |
| 2 | BBBB | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
| 3 | CCCC | 交友,乒乓球 |
+-----+-------+---------------------------------+
3 rows in set (0.00 sec)
这样避免了第5条记录被选中。
当然也可以利用这种正则式 ',阅读,|,交友,|,围棋,|,足球,|,滑雪,', 但效率显然不如 ',(阅读|交友|围棋|足球|滑雪),' 这种了。
参考:
https://blog.****.net/yangpeng201203/article/details/42640257
https://blog.****.net/weixin_34075268/article/details/94242105