当列包含 utf-8 字符时 MySQL 查询返回错误数据

标签 mysql sql

我有一些 MySQL 表,其中“title”列的类型为 varchar(255),字符集为 utf8mb4,排序规则为 utf8mb4_general_ci。

假设我有一些带有标题的记录,并且这些标题包含(或不包含)变音符号:

id | title
-----------
1  | zolc
2  | żółć
3  | żołc
4  | zólć

我可以正确插入这些变音符号,并且在选择表格时它们也会正确显示。但是当我尝试这样的事情时:

SELECT * 
FROM my_table 
WHERE title LIKE "%zolc%";

我得到了:

id | title
-----------
1  | zolc
4  | zólć

如您所见,我要求提供没有任何变音符号的版本,但也得到了 id 为 4 的行。选择 żółć 返回 id 为 2(如预期)和 3 的行。查询 zołć 返回第 2 行和第 3 行,我预计不会返回任何内容。像这样的组合有很多,查询后会返回一些“错误”的行(我也尝试过使用 ąę,它们也表现得很奇怪)。

起初我认为这是我的技术堆栈(Spring Boot之上的Java Web应用程序)的配置问题,但是当我在Windows机器上的本地数据库上从MySQL Workbench执行查询并通过执行查询时得到了完全相同的结果通过 ssh 到 Ubuntu 机器上运行的远程数据库。使用 title LIKE "value" 或使用 WHERE title = "value" 进行查询也没有区别。

我找不到对此的解释 - 请注意,这并不简单地返回“匹配”查询参数但不包含特殊字符的所有行。我正在努力启用按标题搜索,但我希望它是 1:1,因此当我在查询参数中使用“ż”时,只会返回实际存在“ż”的行。

预先感谢您的帮助。

最佳答案

您的查询将使用表/列排序规则,并且由于该排序规则将所有这些字符视为等效,因此您实际上并不需要您认为的值。您的选择是使用适当的文化设置(例如 utf8mb4_polish_ci)或不使用(例如 utf8mb4_bin)。选择哪个选项取决于您的用例,但两者都可能比仅使用某些任意设置更好:utf8mb4_general_ci 是一种一刀切的排序规则,旨在提高速度而不是正确性。

MySQL 允许在不同级别设置排序规则也是毫无值(value)的:

  • 表格
  • 特定字符串

再说一次,选择哪一个将取决于您的具体需求。这是最后一种情况的一个小例子(其他情况很简单):

SELECT
CASE WHEN 'zolc' COLLATE utf8mb4_general_ci ='zólć' THEN 'equal' ELSE 'different' END AS General,
CASE WHEN 'zolc' COLLATE utf8mb4_unicode_ci ='zólć' THEN 'equal' ELSE 'different' END AS Unicode,
CASE WHEN 'zolc' COLLATE utf8mb4_polish_ci ='zólć' THEN 'equal' ELSE 'different' END AS Polish,
CASE WHEN 'zolc' COLLATE utf8mb4_bin ='zólć' THEN 'equal' ELSE 'different' END AS BinaryCollation,
CASE WHEN BINARY 'zolc'='zólć' THEN 'equal' ELSE 'different' END AS BinaryOperator;
General | Unicode | Polish    | BinaryCollation | BinaryOperator 
------- | ------- | --------- | --------------- | -------------- 
equal   | equal   | different | different       | different

(我假设文本是波兰语,如果不是,抱歉。)

关于当列包含 utf-8 字符时 MySQL 查询返回错误数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41245761/

相关文章:

MySQL IF Case Exists 检查用户是否已附加

java - Spring hibernate : SQLQuery involving mapped entities

sql - 根据没有 JOIN 的第二个表从一个表中选择

sql - 如何在 sql 中的单个查询中获取类别和子类别? (mysql)

MySQL varchar 列已填充但不可见

MySQL时区困惑

mysql - 如何在 SQL 中使用带有 IN 运算符的 JSON 字符串列?

SQL - STRING_SPLIT 字符串位置

带有 ORDER BY 的 Android SQLite 负值

mysql - 查找薪资表中缺失的员工