MySQL select UTF-8 字符串带有 '=' 但不带有 'LIKE'
MySQL select UTF-8 string with '=' but not with 'LIKE'
我有一个 table,里面有一些来自中世纪书籍的单词,还有一些在现代 latin1 字母表中不再存在的重音字母。我可以很容易地用 UTF-8 组合字符来表示这些字母。例如,要创建带有波浪号的 "J",我使用 UTF-8 序列 \u004A+\u0303 并且 J 变成重音波浪号。
table使用utf8编码,字段排序规则为utf8_unicode_ci。
我的问题如下:如果我尝试 select 整个字符串,我会收到正确的答案。如果我尝试使用 'LIKE' select,我会收到错误的答案。
例如:
mysql> select word, hex(word) from oldword where word = 'hua';
+--------+--------------+
| word | hex(word) |
+--------+--------------+
| hũa | 6875CC8361 |
| huã | 6875C3A3 |
| hua | 687561 |
| hũã | 6875CC83C3A3 |
+--------+--------------+
4 rows in set (0,04 sec)
mysql> select word, hex(word) from oldword where word like 'hua';
+-------+------------+
| word | hex(word) |
+-------+------------+
| huã | 6875C3A3 |
| hua | 687561 |
+-------+------------+
2 rows in set (0,04 sec)
我不想只搜索整个单词。我想搜索以某个子字符串开头的单词。最终搜索到的词是整个词。
我如何 select 使用 like 的部分字符串并匹配所有字符串?
我尝试使用 this information 创建自定义排序规则,但服务器变得不可用 table 并且只有在经过大量试验和错误之后我才能恢复到 utf8_unicode_ci再次整理,服务器恢复正常。
编辑: 这个网站有问题,有些字符不能正确显示。请查看这些 pastebin 上的结果:
您可以像通配符一样使用 % 符号。例如:
SELECT word
FROM myTable
WHERE word LIKE 'hua%';
这将拉取所有以 hua 开头且后跟 0+ 个字符的记录。这是一个 SQL Fiddle 示例。
问题是 LIKE
逐个字符地进行比较,当使用 "combining tilda" 时,它实际上是两个字符,尽管它显示为一个(假设您的客户端支持显示它因此)。
永远不会出现比较例如hu~a
到 hua
逐个字符匹配,因为它比较 ~
和 a
的第三个字符。
排序规则(和强制转换)对您有利并在比较整个字符串时处理此类事情,但在逐个字符比较时则不然。
即使您考虑使用 SUBSTRING()
作为 hack 而不是使用 LIKE
和通配符 %
来执行前缀搜索,请考虑以下几点:
SELECT SUBSTRING('hũa', 1, 3) = 'hua'
-> 0
SELECT SUBSTRING('hũa', 1, 4) = 'hua'
-> 1
你必须知道你想要的长度或者像这样强行计算:
SELECT * FROM oldword
WHERE SUBSTRING(word, 1, 3) = 'hua'
OR SUBSTRING(word, 1, 4) = 'hua'
OR SUBSTRING(word, 1, 5) = 'hua'
OR SUBSTRING(word, 1, 6) = 'hua'
看到 Marcus Adams 的回答后,我意识到 REPLACE 函数可能是解决这个问题的方法,尽管他没有提到这个函数。
因为我只有两个不同的组合字符(尖音符和波浪号),与其他 ASCII 字符组合,例如 j 带波浪号,j 带尖音符,m 带波浪号,s 带波浪号,等等。我只需要在使用 LIKE 时替换这两个字符即可。
搜索手册后,我了解了 UNHEX 函数,它帮助我在查询中正确表示单独的组合字符以将其删除。
组合波浪号在十六进制代码中用 CC83
表示,锐音符在十六进制代码中用 CC81
表示。
所以,解决我问题的查询就是这个。
SELECT word, REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
FROM oldword WHERE REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
LIKE 'hua%';`
根据this:
ũ
在 5.6.
上的所有 utf8 归类中归类等于普通 U
在大多数排序中,j́
排序等同于普通 J
;例外:
utf8_general*ci
因为其实是j
加上重音。并且 "general" 归类一次只查看一个 character(与 byte 不同)。大多数排序规则都会考虑多个字符,例如西班牙语中的 ch
或 ll
或德语中的 ss
。
utf8_roman_ci
,真是个怪人。 j́=i=j
(LIKE
不完全遵循常规整理规则。我不熟悉细节,但我认为 J
表示为 2 个字符导致它在 LIKE
比 WHERE
或 ORDER BY
。此外,我不知道 REPLACE()
是否像 LIKE
或其他地方那样整理。)
我有一个 table,里面有一些来自中世纪书籍的单词,还有一些在现代 latin1 字母表中不再存在的重音字母。我可以很容易地用 UTF-8 组合字符来表示这些字母。例如,要创建带有波浪号的 "J",我使用 UTF-8 序列 \u004A+\u0303 并且 J 变成重音波浪号。
table使用utf8编码,字段排序规则为utf8_unicode_ci。
我的问题如下:如果我尝试 select 整个字符串,我会收到正确的答案。如果我尝试使用 'LIKE' select,我会收到错误的答案。
例如:
mysql> select word, hex(word) from oldword where word = 'hua';
+--------+--------------+
| word | hex(word) |
+--------+--------------+
| hũa | 6875CC8361 |
| huã | 6875C3A3 |
| hua | 687561 |
| hũã | 6875CC83C3A3 |
+--------+--------------+
4 rows in set (0,04 sec)
mysql> select word, hex(word) from oldword where word like 'hua';
+-------+------------+
| word | hex(word) |
+-------+------------+
| huã | 6875C3A3 |
| hua | 687561 |
+-------+------------+
2 rows in set (0,04 sec)
我不想只搜索整个单词。我想搜索以某个子字符串开头的单词。最终搜索到的词是整个词。
我如何 select 使用 like 的部分字符串并匹配所有字符串?
我尝试使用 this information 创建自定义排序规则,但服务器变得不可用 table 并且只有在经过大量试验和错误之后我才能恢复到 utf8_unicode_ci再次整理,服务器恢复正常。
编辑: 这个网站有问题,有些字符不能正确显示。请查看这些 pastebin 上的结果:
您可以像通配符一样使用 % 符号。例如:
SELECT word
FROM myTable
WHERE word LIKE 'hua%';
这将拉取所有以 hua 开头且后跟 0+ 个字符的记录。这是一个 SQL Fiddle 示例。
问题是 LIKE
逐个字符地进行比较,当使用 "combining tilda" 时,它实际上是两个字符,尽管它显示为一个(假设您的客户端支持显示它因此)。
永远不会出现比较例如hu~a
到 hua
逐个字符匹配,因为它比较 ~
和 a
的第三个字符。
排序规则(和强制转换)对您有利并在比较整个字符串时处理此类事情,但在逐个字符比较时则不然。
即使您考虑使用 SUBSTRING()
作为 hack 而不是使用 LIKE
和通配符 %
来执行前缀搜索,请考虑以下几点:
SELECT SUBSTRING('hũa', 1, 3) = 'hua'
-> 0
SELECT SUBSTRING('hũa', 1, 4) = 'hua'
-> 1
你必须知道你想要的长度或者像这样强行计算:
SELECT * FROM oldword
WHERE SUBSTRING(word, 1, 3) = 'hua'
OR SUBSTRING(word, 1, 4) = 'hua'
OR SUBSTRING(word, 1, 5) = 'hua'
OR SUBSTRING(word, 1, 6) = 'hua'
看到 Marcus Adams 的回答后,我意识到 REPLACE 函数可能是解决这个问题的方法,尽管他没有提到这个函数。
因为我只有两个不同的组合字符(尖音符和波浪号),与其他 ASCII 字符组合,例如 j 带波浪号,j 带尖音符,m 带波浪号,s 带波浪号,等等。我只需要在使用 LIKE 时替换这两个字符即可。
搜索手册后,我了解了 UNHEX 函数,它帮助我在查询中正确表示单独的组合字符以将其删除。
组合波浪号在十六进制代码中用 CC83
表示,锐音符在十六进制代码中用 CC81
表示。
所以,解决我问题的查询就是这个。
SELECT word, REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
FROM oldword WHERE REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
LIKE 'hua%';`
根据this:
ũ
在 5.6.
U
在大多数排序中,j́
排序等同于普通 J
;例外:
utf8_general*ci
因为其实是j
加上重音。并且 "general" 归类一次只查看一个 character(与 byte 不同)。大多数排序规则都会考虑多个字符,例如西班牙语中的ch
或ll
或德语中的ss
。utf8_roman_ci
,真是个怪人。j́=i=j
(LIKE
不完全遵循常规整理规则。我不熟悉细节,但我认为 J
表示为 2 个字符导致它在 LIKE
比 WHERE
或 ORDER BY
。此外,我不知道 REPLACE()
是否像 LIKE
或其他地方那样整理。)