SQL没有区分你和ü虽然整理是utf8mb4_unicode_ci

时间:2016-12-12 13:50:04

标签: mysql sql utf-8 utf utf8mb4

在表格x中,有一列的值为uü

SELECT * FROM x WHERE column='u'

这会返回uü,但我只是在寻找u

表的排序规则为utf8mb4_unicode_ci。无论我在哪里阅读类似问题,每个人都建议使用这种排序规则,因为他们说utf8mb4确实涵盖了所有字符。通过这种整理,所有字符集和整理问题都应该得到解决。

我可以插入üèéàChinese characters等。当我制作SELECT *时,它们是也正确检索和显示。

只有当我按照上面的示例(SELECT WHERE)比较两个字符串或在列上使用UNIQUE INDEX时,才会出现此问题。当我使用UNIQUE INDEX时,如果列中已有"ü",则不会插入"u"。因此,当SQL比较uü以确定ü是否唯一时,它会认为它与u相同,并且不会插入ü

我将所有内容都更改为utf8mb4因为我不想再担心字符集和排序规则了。但是,当涉及到COMPARING字符串时,utf8mb4似乎不是解决方案。

我也试过这个: SELECT * FROM x WHERE _utf8mb4 'ü' COLLATE utf8mb4_unicode_ci = column
此代码是可执行的(看起来非常复杂)。但是,它还会返回üu

我已经和印度的一些人和中国的人谈过这个问题。我们还没有找到解决方案。

如果有人能解开这个谜团,那真的很棒。

Add_On:阅读下面的所有答案和评论后,这是一个解决问题的代码示例:

SELECT * FROM xWHERE'ü' COLLATE utf8mb4_bin = column

通过在SELECT查询中添加“COLLATE utf8mb4_bin”,SQL会在查看列中的字符时将“二元眼镜”(结束_bin)置于其上。在打开二进制眼镜的情况下,SQL现在可以看到列中的二进制代码。并且二进制代码对于每个可以想到的字母和字符以及表情符号都是不同的。所以,SQL现在也可以看到u和ü之间的区别。因此,现在它只在SELECT查询查找ü时返回ü,并且不返回u。

通过这种方式,可以保留所有内容(数据库排序规则,表格排序规则),但只有在需要精确区分时才将“COLLATE utf8mb4_bin”添加到查询中。

(实际上,SQL会关闭所有其他眼镜(utf8mb4_german_ci,_general_ci,_unicode_ci等)并且只执行它在没有被强制执行任何额外操作时所执行的操作。它只是查看二进制代码而不调整其寻找任何特殊的文化背景。)

感谢大家的支持,尤其是对Pred的支持。

4 个答案:

答案 0 :(得分:7)

整理和字符集是两回事。

字符集只是一个'无序'字符列表及其表示。 utf8mb4是一个字符集,涵盖了很多字符。

校对定义字符的顺序(例如,确定顺序的最终结果)并定义其他规则(例如应将哪些字符或字符组合视为相同)。排序是从字符集派生的,对于同一字符集可以有多个排序规则。 (它是字符集的扩展 - sorta)

utf8mb4_unicode_ci中,所有(大多数?)重音字符都被视为同一个字符,这就是您获得uü的原因。简而言之,这种整理是一种非常不敏感的整理。

这类似于德国排序规则将ssß视为相同的事实。

utf8mb4_bin是另一种排序规则,它将所有字符视为不同的字符。您可能希望也可能不希望将其用作默认设置,这取决于您和您的业务规则。

您还可以在查询中转换排序规则,但请注意,这样做会阻止MySQL使用索引。

以下是一个使用相似但可能更熟悉的排序规则的示例:

归类结尾处的ci表示Case Insensitive,而ci的几乎所有归类都有一对以cs结尾,即Case Sensitive。< / p>

当你的列不区分大小写时,where条件column = 'foo'会找到所有这些:foo Foo Foo FOo FoO fOO,FOO。

现在,如果您尝试将排序规则设置为区分大小写(例如utf8mb4_unicode_cs),则所有上述值都将被视为不同的值。

本地化的排序规则(如德语,英国,美国,匈牙利等)遵循指定语言的规则。在德国,ssß是相同的,这在德语规则中有说明。当德国用户搜索值Straße时,他们会希望软件(支持德语或德语编写)同时返回StraßeStrasse

更进一步,在订购方面,这两个词是相同的,它们是相同的,它们的含义是相同的,所以没有特定的顺序。

不要忘记,UNIQUE约束只是排序/过滤值的一种方式。因此,如果在具有德语排序规则的列上定义了唯一键,则不允许同时插入StraßeStrasse,因为根据语言规则,它们应被视为相等。< / p>

现在让我们看看我们的原始排序规则:utf8mb4_unicode_ci,这是一种“通用”排序规则,这意味着它会尝试简化所有内容,因为ü不是一个非常常见的字符且大多数用户都有不知道如何输入,这种排序使其等于u。这是为了支持大多数语言的简化,但正如您所知,这些简化会产生一些副作用。 (如在排序,过滤,使用唯一约束等)。

utf8mb4_bin是频谱的另一端。这种整理设计尽可能严格。为此,它实际上使用字符代码来区分字符。这意味着,角色的每种形式都是不同的,这种整理是隐含的区分大小写和区分重音。

这两者都有缺点:本地化和通用排序规则是针对一种特定语言设计的,或提供一种通用解决方案。 (utf8mb4_unicode_ci是旧utf8_general_ci归类)的“扩展名”

二进制文件在用户交互方面需要格外小心。由于它是CSAS,因此当他们查找值'foo'时,可能会混淆用于获取值'Foo'的用户。此外,作为开发人员,在连接和其他功能方面,您必须格外小心。 INNER JOIN'foo'='Foo'将不返回任何内容,因为'foo'不等于'Foo'。

我希望这些例子和解释有所帮助。

答案 1 :(得分:4)

utf8_collations.html列出了各种utf8(或utf8mb4)排序规则中的字母“相等”。除了极少数例外,在任何 ..._ci排序规则中进行比较之前,所有重音都会被删除。一些例外是特定于语言的,而不是一般的Unicode。示例:在冰岛É > E

..._bin是唯一一种将对待重音字母视为不同的校对。案件折叠同样如此。

如果要进行大量比较,则应将列的排序规则更改为..._bin。在COLLATE中使用WHERE子句时,无法使用索引。

关于ß的说明。几乎所有排序规则中都ss = ß。特别是,utf8_general_ci(曾经是默认值)将它们视为不相等。 一个排序规则不会将任何双字母组合(ss)视为单个“字母”。此外,由于5.0中的错误,utf8_general_mysql500_ci将它们视为不相等。

展望未来,utf8mb4_unicode_520_ci是5.7版本中最好的。对于8.0,utf8mb4_0900_ai_ci是“更好”。 “520”和“900”指的是Unicode标准,因此将来可能会有更新的标准。

答案 2 :(得分:0)

您可以尝试使用utf8_bin排序规则并且您不应该面对此问题,但它会区分大小写。 bin整理严格比较,只根据所选的编码将字符分开,一旦完成,比较就在二进制基础上完成,就像许多编程语言比较字符串一样。

答案 3 :(得分:0)

我只是在其他答案中加上_bin整理有其特殊性。

例如,在以下情况之后:

CREATE TABLE `dummy` (`key` VARCHAR(255) NOT NULL UNIQUE);
INSERT INTO `dummy` (`key`) VALUES ('one');

这将失败:

INSERT INTO `dummy` (`key`) VALUES ('one ');

The binary Collation Compared to _bin Collations中描述了这一点。

修改:我发布了一个相关问题here