当前位置: 首页 > 科技观察

MySQL模式匹配查询分析(标准SQL模式匹配和正则模式匹配)

时间:2023-03-13 15:15:53 科技观察

在业务开发中,经常需要对某个字段进行模糊匹配。例如,通过某个名字进行匹配,但用户可能只记住了一些单词,而没有记住全名。如果能支持模糊匹配,用户体验会好很多。MySQL提供标准SQL模式匹配以及基于扩展正则表达式的模式匹配,类似于vi、grep和sed等Unix实用程序所使用的模式。SQL模式匹配SQL模式匹配使您能够将任何单个字符与“_”匹配,将任意数量的字符(包括零个字符)与“%”匹配。在MySQL中,默认情况下SQL模式不区分大小写。使用SQL模式时不要使用=或<>,而是使用LIKE或NOTLIKE运算符。要查找以b开头的名称:mysql>SELECT*FROMpetWHEREnameLIKE'b%';+------+--------+----------+------+------------+------------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+--------+------+------------+--------------+|巴菲|哈罗德|狗|f|1989-05-13|空||鲍泽|------+--------+--------+------+------------+----------+查找以fy结尾的名称:mysql>SELECT*FROMpetWHEREnameLIKE'%fy';+--------+--------+--------+--------+------------+------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+--------+------+------------+-------+|蓬松|哈罗德|猫|f|1993-02-04|空||巴菲|哈罗德|+--------+--------+------+------------+--------+查找包含w的名称:mysql>SELECT*FROMpetWHEREnameLIKE'%w%';+----------+--------+--------+------+------------+------------+|姓名|拥有者|物种|性别|诞生|死亡|+------------+--------+--------+------+------------+------------+|爪子|格温|猫|m|1994-03-17|NULL||鲍泽|黛安|狗|m|1989-08-31|1995-07-29||惠斯勒|格温|鸟|空|1997-12-09|----------+------+------------+------------+找到恰好五个字符请使用模式字符“_”:mysql>SELECT*FROMpetWHEREnameLIKE'_____';+------+--------+---------+------+------------+--------+|姓名|拥有者|物种|性别|诞生|死亡|+-------+--------+--------+------+----------+------+|爪|格温|猫|米|1994-03-17|空||巴菲|哈罗德|+--------+-----+------------+--------+正则模式匹配一般情况下,以上函数都有been可以满足大部分业务的开发需求,但是偶尔会遇到一些比较复杂的查询匹配需求,可能需要正则化来满足。MySQL提供的另一种模式匹配使用扩展的正则表达式。当您测试与此类模式的匹配时,请使用REGEXP和NOTREGEXP运算符(或RLIKE和NOTRLIKE,它们是同义词)。个人比较喜欢RLIKE和NOTRLIKE,它们类似于LIKE和NOTLIKE,也好记。.匹配任何单个字符。字符类[...]匹配方括号内的任何字符。例如,[abc]匹配a、b或c。要命名一系列字符,请使用破折号,[a-z]匹配任何字母,[0-9]匹配任何数字。*匹配它前面的事物的零个或多个实例。例如,x*匹配任意数量的x个字符,[0-9]*匹配任意数量的数字,而.*匹配任意数量的任何内容。如果模式匹配被测试值中的任何位置,则正则表达式模式匹配成功。(这与LIKE模式匹配不同,后者只有在模式匹配整个值时才会成功。)要锚定一个模式,使其必须匹配被测试值的$的开头或结尾,请在$的开头或结尾包含该模式使用。为了演示扩展正则表达式的工作原理,前面显示的LIKE查询在此处使用正则表达式重写。要查找以b开头的名称,请使用^匹配名称的开头:mysql>SELECT*FROMpetWHEREnameREGEXP'^b';+--------+--------+--------+-----+------------+------------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+--------+------+----------+------------+|巴菲|哈罗德|狗|f|1989-05-13|07-29|+--------+--------+--------+------+------------+------------+要强制REGEXP比较区分大小写,请使用BINARY关键字使其中一个字符串成为二进制字符串。此查询仅匹配以b名称开头的小写字母:SELECT*FROMpetWHEREnameREGEXPBINARY'^b';要查找以fy结尾的名称,请使用$匹配名称的末尾:mysql>SELECT*FROMpetWHEREnameREGEXP'fy$';+--------+--------+----------+------+-------------+------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+---------+------+----------+------+|蓬松|哈罗德|猫|f|1993-02-04|空||哈罗德|狗|f|1989-05-13|空|+--------+--------+--------+------+----------+-------+要查找包含w的名称,请使用以下查询:mysql>SELECT*FROMpetWHEREnameREGEXP'w';+---------+--------+--------+------+------------+--------------+|姓名|拥有者|物种|性别|诞生|死亡|+------------+--------+---------+------+------------+------------+|爪|格温|猫|米|1994-03-17|空||鲍泽|黛安|狗|米|1989-08-31|1995-07-29||惠斯勒|-+--------+--------+------+------------+------------+因为正则表达式模式将匹配值中的任何位置,之前的查询,它不是有必要在模式的两边放置通配符以使其与SQL模式中的整个值匹配要查找恰好包含五个字符的名称,请使用^,$,。匹配名称的开头和结尾:mysql>SELECT*FROMpetWHEREnameREGEXP'^.....$';+-------+--------+---------+--------+------------+--------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+--------+-----+-----------+-------+|爪|格温|猫|米|1994-03-17|空||巴菲|哈罗德|空|+--------+--------+--------+------+------------+------+您还可以使用{n}(“重复n次”)运算符:mysql>SELECT*FROMpetWHEREnameREGEXP'^.{5}$';+-------+--------+--------+------+------------+------+|姓名|拥有者|物种|性别|诞生|死亡|+--------+--------+--------+-----+----------+-------+|爪|格温|猫|米|1994-03-17|空||巴菲|哈罗德||空|+--------+--------+--------+------+---------+-------+注意事项两种模式匹配的区别Like匹配的原理是只有当模式字符串与整个目标字段匹配时才返回记录。正则匹配是当目标字段包含模式字符串时返回记录。模式匹配可能无法使用索引。InnoDB在模糊查询数据时使用“%xx”会导致索引失败,正则模式类似。最好和其他索引字段一起查询,效率更高。如果数据量很大,建议使用全文索引。正则匹配注意特殊字符正则匹配功能强大,但是使用的时候一定要注意特殊字符的干扰,尤其是在mysql中检查括号或者括号的时候,一定要转义:mysql>SELECTREGEXP_LIKE('(','(');错误3692(HY000):正则表达式中的括号不匹配.mysql>SELECTREGEXP_LIKE('(','\\(');+-------------------------+|REGEXP_LIKE('(','\\(')|+------------------------+|1|+------------------------+mysql>SELECTREGEXP_LIKE(')',')');错误3692(HY000):正则表达式中的括号不匹配.mysql>SELECTREGEXP_LIKE(')','\\)');+------------------------+|REGEXP_LIKE(')','\\)')|+------------------------+|1|+----------------------+mysql>SELECTREGEXP_LIKE('[','[');ERROR3696(HY000):常规表达式包含一个未闭合的括号表达式。mysql>SELECTREGEXP_LIKE('[','\\[');+------------------------+|REGEXP_LIKE('[','\\[')|+------------------------+|1|+------------------------+mysql>SELECTREGEXP_LIKE(']',']');+----------------------+|REGEXP_LIKE(']',']')|+----------------------+|1|+--------------------+解决方法:限制使用的字符范围,查询前排除元素转义字符。例如,在golang中,使用funcQuoteMeta(sstring)stringQuoteMeta返回一个字符串,该字符串对参数文本内部的所有正则表达式元字符进行转义;返回的字符串是匹配文字文本的正则表达式。