假设我的 wiki (MediaWiki 1.19.4) 中有这些页面标题:
SOMETHIng
Sómethìng
SomêthÏng
SÒmetHínG
如果用户搜索something
我希望所有 4 页都作为结果返回。
目前我唯一能想到的是这个查询(MySQL Percona 5.5.30-30.2):
SELECT page_title
FROM page
WHERE page_title LIKE '%something%' COLLATE utf8_general_ci
哪个只返回SOMETHIng
.
我一定走在正确的道路上,因为如果我搜索sóméthíng
OR SÓMÉTHÍNG
, I get SOMETHIng
作为结果。如何修改查询以便获得预期的其他结果?性能在这里并不重要,因为page
表仅包含约 2K 行。
这是带有相关位的表定义:
CREATE TABLE page (
(...)
page_title VARCHAR(255) NOT NULL DEFAULT '' COLLATE latin1_bin,
(...)
UNIQUE INDEX name_title (page_namespace, page_title),
)
表定义must not进行修改,因为这是 MediaWiki 的库存安装,据我所知,其代码期望以这种方式定义该字段(即存储为二进制数据的 unicode)。
我找到了完美的解决方案,无需修改或创建表。它might对性能有影响(我没有测试),但正如我在问题中所说,它是一个约 2K 行的表,所以它应该不重要。
问题的根源在于MediaWiki 将 UTF8 编码文本存储在 latin1 编码表中。这对 MediaWiki 来说并不重要,因为它知道这一点,并且它总是会使用正确的字符集查询数据库并执行其操作,本质上使用 MySQL 作为哑位容器。这样做是因为显然 MySQL 中的 UTF8 支持不足以满足其需求(请参阅 MediaWiki 中的评论)DefaultSettings.php
, 多变的$wgDBmysql5
).
当您希望数据库本身能够执行 UTF8 感知操作(就像我在问题中想做的那样)时,就会出现问题。你将无法做到这一点,因为据 MySQL 所知,它不存储 UTF8 编码的文本(尽管如此,如前一段所述)。
有一个明显的解决方案:将您要使用的列转换为 UTF8,如下所示CONVERT(col_name USING utf8)
。这里的问题是 MySQL 试图提供危险的帮助:它认为col_name
正在存储 latin1 编码的文本,它将翻译(而不是编码)每个字节转换成它的 UTF8 等价物,你将以双编码的 UTF8 结束,这显然是错误的。
如何避免 MySQL 变得如此友善和乐于助人?只是转换为二进制before正在转换为 UTF8!这样 MySQL 就不会做出任何假设,并且会完全按照要求执行:将这串位编码为 UTF8。确切的语法是CONVERT(CAST(col_name AS BINARY) USING utf8)
.
所以这是我现在的最后一个查询:
SELECT CONVERT(CAST(page_title AS BINARY) USING utf8)
FROM page
WHERE
CONVERT(CAST(page_title AS BINARY) USING utf8)
LIKE '%keyword_here%'
COLLATE utf8_spanish_ci
现在如果我搜索something
or sôMëthîNG
或任何变化,我得到所有结果!
请注意,我使用了utf8_spanish_ci
因为我希望搜索能够区分ñ
from n
但不是á
from a
。根据您的用例使用不同的排序规则(这是完整的列表).
相关链接:
- MySQL:将不正确的 latin1 列转换为 utf8
- MySQL如何在UTF-8中“不区分大小写”和“不区分重音”
- MySQL 5.5 中可用的排序规则
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)