REGEXP 正则的实现两个字符串组的匹配。

最近MySQL版块中相似问题出现得比较多。总结了一下。

 

因为某些缘由,有时候咱们没有按照范式的设计准则而把一些属性放到同一个字符串字段中。好比我的兴趣,有时候咱们设计表为
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条记录被选中。

 

固然也能够利用这种正则式 ',阅读,|,交友,|,围棋,|,足球,|,滑雪,', 但效率显然不如 ',(阅读|交友|围棋|足球|滑雪),' 这种了。

 

参考文档:

 

MySQL 5.1参考手册 - 12.3.1. 字符串比较函数 - REGEXP (RLIKE)

http://dev.mysql.com/doc/refman/5.1/zh/functions.html#string-comparison-functions

 

MySQL 5.1参考手册 - 附录G:MySQL正则表达式

http://dev.mysql.com/doc/refman/5.1/zh/regexp.html

相关文章
相关标签/搜索