在我的理解中mysql本身就对中文支持不好,如果我们再在操作时有一点小不标准那么查出来的中文就更乱了,下面我来给大家介绍mysql中文模糊查找不精确解决办法
例如,通过“标题”对新闻库进行检索,关键字可能包含是中英文,如下SQL语句:
select id,title,name from achech_com.news where title like '%a%'
返回的结果,某些title字段确定带了“a”关键字,而有些则只有中文,但也随之返回在检索结果中。
解决方法,使用 BINARY 属性进行检索:
select id,title,name from achech_com.news where binary title like '%a%'
返回的结果较之前正确,但英文字母区分大小写,故有时在检索如“Achech”及“achech”的结果是不一样的。知道了使用 BINARY 属性可以解决前面这个问题,再看看 MySQL 支持的UCASE 及 CONCAT 函数,其中 UCASE 是将英文全部转成大写,而CONCAT函数的作用是对字符进行连接,以下是完全解决后的SQL 语句:
select id,title,name from achech_com.news where binary ucase(title) like concat('%',ucase('a'),'%')
检索的步骤是先将属性指定为 BINARY ,以精确检索结果,而被 like 的 title内容存在大小写字母的可能,故先使用 ucase 函数将字段内容全部转换成大写字母,然后再进行 like 操作,而 like 的操作使用模糊方法,使用 concat的好处是传进来的可以是直接的关键字,不需要带“%”万用符,将“'a'”直接换成你的变量,在任何语言下都万事无忧了,当然你也可以这么写:
select id,title,name from achech_com.news where binary ucase(title) like ucase('%a%')
另一种办法,性能更高,MySQL全文检索.
1.MySQL 4.x版本及以上版本提供了全文检索支持,但是表的存储引擎类型必须为MyISAM,以下是建表SQL,注意其中显式设置了存储引擎类型.
- CREATETABLEarticles(
- idINTUNSIGNEDAUTO_INCREMENTNOTNULLPRIMARYKEY,
- titleVARCHAR(200),
- bodyTEXT,
- FULLTEXT(title,body)
- )ENGINE=MyISAMDEFAULTCHARSET=utf8;
其中FULLTEXT(title, body) 给title和body这两列建立全文索引,之后检索的时候注意必须同时指定这两列。
2. 插入测试数据
- INSERTINTOarticles(title,body)VALUES
- ('MySQLTutorial','DBMSstandsforDataBase...'),
- ('HowToUseMySQLWell','Afteryouwentthrougha...'),
- ('OptimizingMySQL','Inthistutorialwewillshow...'),
- ('1001MySQLTricks','1.Neverrunmysqldasroot.2....'),
- ('MySQLvs.YourSQL','Inthefollowingdatabasecomparison...'),
- ('MySQLSecurity','Whenconfiguredproperly,MySQL...');
3.全文检索测试
SELECT * FROM articlesWHERE MATCH (title,body) AGAINST ('database');
检索结果如下:
MySQL vs. YourSQL In the following database comparison ...1
MySQL Tutorial DBMS stands for DataBase ... 说明全文匹配时忽略大小写.
4.可能遇到的困扰
到目前为止都很顺利,但是如果检索SQL改为下面会怎样呢?
SELECT * FROM articlesWHERE MATCH (title,body) AGAINST ('well'); 结果让人大跌眼镜,开始我也困惑了许久,后来去网上查了下才知道原来是这么回事.
mysql指定了最小字符长度,默认是4,必须要匹配大于4的才会有返回结果,可以用SHOW VARIABLES LIKE 'ft_min_word_len' 来查看指定的字符长度,也可以在mysql配置文件my.ini 更改最小字符长度,方法是在my.ini 增加一行 比如:ft_min_word_len = 2,改完后重启mysql即可。 所以上面不能返回结果。但是我用上面的方法改配置文件并重启MySQL服务器后,再用show命令查看,并没有改变。
另外,MySQL还会计算一个词的权值,以决定是否出现在结果集中,具体如下:
mysql在集和查询中的对每个合适的词都会先计算它们的权重,一个出现在多个文档中的词将有较低的权重(可能甚至有一个零权重),因为在这个特定的集中,它有较低的语义值。否则,如果词是较少的,它将得到一个较高的权重,mysql默认的阀值是50%,上面‘you’在每个文档都出现,因此是100%,只有低于50%的才会出现在结果集中。 但是如果不考虑权重,那么该怎么办呢?MySQL提供了布尔全文检索(BOOLEAN FULLTEXT SEARCH)
假设well在所有记录中都出现,并且ft_min_word_len已经改为2,那么下面的SQL检索语句得到的结果集将包含所有记录:
SELECT * FROM articles WHERE MATCH (title,body)AGAINST ('well' IN BOOLEAN MODE );//phpfensi.com
5.布尔全文检索语法
上面通过IN BOOLEAN MODE指定全文检索模式为布尔全文检索,MySQL还提供了一些类似我们平时使用seo/seo.html" target="_blank">搜索引擎时用到的的语法,逻辑与、逻辑或、逻辑非等,具体通过几个SQL语句例子来说明.
SELECT * FROM articles WHERE MATCH (title,body)
AGAINST ('+apple -banana' IN BOOLEAN MODE); + 表示AND,即必须包含。- 表示NOT,即不包含。
SELECT * FROM articles WHERE MATCH (title,body)
AGAINST ('apple banana' IN BOOLEAN MODE); apple和banana之间是空格,空格表示OR,即至少包含apple、banana中的一个。
SELECT * FROM articles WHERE MATCH (title,body)
AGAINST ('+apple banana' IN BOOLEAN MODE); 必须包含apple,但是如果同时也包含banana则会获得更高的权重。
SELECT * FROM articles WHERE MATCH (title,body)
AGAINST ('+apple ~banana' IN BOOLEAN MODE); ~ 是我们熟悉的异或运算符。返回的记录必须包含apple,但是如果同时也包含banana会降低权重。但是它没有 +apple -banana 严格,因为后者如果包含banana压根就不返回。
SELECT * FROM articles WHERE MATCH (title,body)AGAINST ('+apple +(>banana <orange)' IN BOOLEAN MODE);
返回同时包含apple和banana或者同时包含apple和orange的记录,但是同时包含apple和banana的记录的权重高于同时包含apple和orange的记录.