我相信这里的许多人都知道,至少可以说,必须处理德国货币和UTF8排序是有问题的。像a = ä
、o = ö
、u = ü
这样的东西不仅能够影响结果的排序顺序,而且还能影响实际的结果。这里有一个例子,它清楚地说明了事情是如何出错的,只要简单地区分名词的单数和复数(Bademantel
-单数,Bademäntel
-复数)。
CREATE TABLE keywords (
id INT (11) PRIMARY KEY AUTO_INCREMENT,
keyword VARCHAR (255) NOT NULL
) ENGINE = MyISAM DEFAULT CHARACTER
SET = utf8 COLLATE = utf8_unicode_ci;
INSERT INTO keywords (keyword) VALUES ('Bademantel'), ('Bademäntel');
SELECT * FROM keywords WHERE keyword LIKE ('%Bademäntel%');
结果应该是
+----+------------+
| id | keyword |
+----+------------+
| 1 | Bademäntel |
+----+------------+
然而,对于utf8_unicode_ci
,输出是
+----+------------+
| id | keyword |
+----+------------+
| 1 | Bademantel |
| 2 | Bademäntel |
+----+------------+
这显然不是必要的结果。
实际的问题与我目前的项目有关。它涉及到编写一个关键字解析器,这个解析器基本上应该用一个指向相应产品页面的链接来替换网站上出现的每一个关键字。为了避免不必要的资源浪费,只获取不同的关键字,但使用
SELECT keyword FROM keywords GROUP BY keyword ORDER BY LENGTH(keyword) DESC
或
SELECT DISTINCT keyword FROM keywords ORDER BY LENGTH(keyword) DESC
将导致无法处理(链接)所有非语言版本的单词,仅仅是因为它们在查询期间不被获取(也就是说,包含Bademäntel
的所有关键字都将被获取,但Bademantel
将被省略)。
现在我意识到我有几个选择来解决这个问题。
1)在关键字表或查询期间使用utf8_swedish_ci
,这样可以有效地避免修改大量现有代码。
SELECT DISTINCT keyword COLLATE utf8_swedish_ci AS keyword FROM keywords ORDER BY LENGTH(keyword) DESC;
不幸的是,我并不是那么不愿意放弃utf8_unicode_ci
,因为它提供了一个非常好的"Eszett“排序功能(ss
和ß
被认为是相同的),( b)使用瑞典的校勘来处理与德国相关的东西,不知何故,我觉得这是错误的。
2)修改现有代码,利用utf8_bin
。
SELECT DISTINCT keyword COLLATE utf8_bin AS keyword FROM keywords ORDER BY LENGTH(keyword) DESC;
这符合预期,但它有一个令人讨厌的缺点,即所有比较都区分大小写,这意味着如果我决定依赖utf8_bin
作为解决问题的解决方案,我将很难进行像LIKE('%Mäntel%')
这样的不区分大小写的查询,因为它肯定会忽略Bademäntel
之类的记录。
我知道这个问题时有发生,但有些答案现在已经过时了,我只想知道在此期间是否还会出现其他的解决办法。我的意思是,我真的无法回避一个简单的排序规则可以完全改变查询结果的想法。排序顺序是的,但是结果本身呢?
很抱歉发布了一些较长的帖子,并对任何形式的建议或评论表示感谢。
发布于 2015-11-16 13:05:37
对于遇到这个问题的其他人,值得注意的是,自MySQL 5.6以来对utf8_german2_ci
排序规则有官方支持,它解决了上述所有问题。迟到总比我猜的要好。
发布于 2016-08-25 14:16:17
您可以使用关键字WHERE BINARY keyword = 'Bademantel'
进行二进制检查。结果将是预期的结果。
查看这个木琴,它显示如下:
SELECT * FROM stackoverflow WHERE BINARY keyword = 'Bademantel';
| id | keyword |
|----|------------|
| 1 | Bademantel |
SELECT * FROM stackoverflow WHERE keyword = 'Bademantel';
| id | keyword |
|----|------------|
| 1 | Bademantel |
| 2 | Bademäntel |
有关此行为的更多信息,请参见:使用二进制排序规则有什么效果?和德语最好的MySQL排序规则是什么?
因此,对于带有德语、严重口音或捷克/波兰语的特殊字符的应用程序,您必须决定哪种行为最适合您的应用程序。
大多数情况下都可以使用utf8_general_ci
,但有时您必须对Bademantel
这样的情况使用utf8_bin
。
字符串比较一点也不坏,utf8_general_ci
有时会帮助您。如果您保存了一个类似于Straße
的字符串,那么您可以搜索Strasse
,这也将返回Straße
。
https://stackoverflow.com/questions/20953587
复制相似问题