如何设置MySQL以正确处理unicode变音符号?

时间:2013-02-15 20:47:26

标签: mysql unicode utf-8 collation diacritics

这是一个奇怪的难题,AFAIK utf8_bin应该保证每个重音都正确地存储在数据库中,即没有奇怪的转换为ASCII。所以我有这样的表:

DEFAULT CHARSET=utf8 COLLATE=utf8_bin

然而当我尝试比较/查询/根据MySQL的“Krąków”和“Kraków”这样的条目时,这是相同的字符串。

出于好奇,我也尝试了utf8_polish,并且MySQL声称对于波兰人来说“a”和“ą”没有任何区别。

那么如何设置MySQL表,这样我就可以安全地存储unicode字符串,而不会丢失重音等等?

服务器:MySQL 5.5 + openSUSE 11.4,客户端:Windows 7 + MySQL Workbench 5.2。

更新 - CREATE TABLE

CREATE TABLE `Cities` (
  `city_Name` VARCHAR(145) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`city_Name`)
) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

请注意,我无法为列设置不同的 utf8_bin,因为整个表格是utf8_bin,因此实际上列的排序规则会重置为默认值。

2 个答案:

答案 0 :(得分:2)

解决方案的所有学分都归 bobince 所示,所以请在我的问题上投票。

这个问题的解决方案有些奇怪,我冒这么说的风险说MySQL已经破了。

所以,我们说我用utf8创建了一个表,并没有为列做任何事情。后来我意识到我需要严格比较字符,所以我将表和列的排序规则更改为utf8_bin。解决了吗?

不,现在MySQL看到了 - 表确实是utf8_bin,但是列也是utf8_bin,这意味着列使用表的DEFAULT排序规则。但是,MySQL没有意识到先前的默认值与当前默认值不同。因此,比较仍然不起作用。

因此,您必须摆脱列的默认值,以及超出排序范围的某些外来价值"家庭" (如果是" utf8xxx"表示没有其他" utf8xxx")。一旦它被甩掉,你就会看到没有说"默认"在列排序规则中,您可以设置utf8_bin,现在评估为默认值,但由于我们来自非默认排序规则,所有内容都会按预期启动。

不要忘记在每一步都应用更改。

答案 1 :(得分:0)

MySQL默认字符集和排序规则(在服务器范围内,但每个连接可以更改)适用于创建表时。创建表后更改默认值不会影响现有表。

字符集和排序规则是各列的属性。它们可以从表格范围的默认设置,但它们属于列。

utf8的字符集应足以允许所有欧洲语言正确表示。你绝对应该能够将“a”和“±”存储为两个不同的字符。

utf8-bin的排序规则会产生一个案例和带重音字符的敏感排序规则。

以下是文本值和归类行为之间差异的一些示例。我正在使用三个示例字符串:'abcd','ĄBCD'和'ąbcd'。最后两个有A-ogonek信。

第一个例子说,使用utf8字符表示和utf8_general_ci排序规则,三个字符串每个都按用户指定显示,但它们比较相等。这是在不区分a和±的整理中预期的。这是一种典型的不区分大小写的排序规则,其中所有变体字符的排序等于没有任何变音标记的字符。

SET NAMES 'utf8' COLLATE 'utf8_general_ci';
SELECT 'abcd', 'ąbcd' , 'abcd' < 'ąbcd',  'abcd' = 'ąbcd';
                               false            true  

下一个例子表明,在不区分大小写的波兰语排序规则中,a出现在±之前。我不懂波兰语,但我怀疑波兰语电话簿中的As和Ą是分开的。

SET NAMES 'utf8' COLLATE 'utf8_polish_ci';
SELECT 'abcd', 'ĄBCD' , 'ąbcd', 'abcd' < 'ĄBCD', 'abcd' < 'ąbcd' , 'ąbcd' = 'ĄBCD' 
                                      true             true              true

下一个示例显示了utf8_bin排序规则会发生什么。

SET NAMES 'utf8' COLLATE 'utf8_bin';
SELECT 'abcd', 'ĄBCD' , 'ąbcd', 'abcd' < 'ĄBCD', 'abcd' < 'ąbcd' , 'ąbcd' = 'ĄBCD' 
                                      true           true               false

在这种情况下,有一个非直观的事情需要注意。 'abcd'&lt; 'ĄBCD'为真(而'abcd'&lt;'带有纯ASCII的ABCD'为假)。如果你在语言上思考,这是一个奇怪的结果。这是因为两个A-ogonek字符在utf8中都具有高于所有abc和ABC字符的二进制值。所以:如果你对ORDER BY操作使用utf8-bin校对,你会得到语言上奇怪的结果。

你说'Krąków'和'Kraków'比较平等,你对此感到困惑。当使用的排序规则是utf8_general_ci时,它们比较相等。但他们没有使用utf8_bin或utf8_polish_ci。根据MySQL中的波兰语支持,这两个城市名称的拼写是不同的。

在设计应用程序时,您需要弄清楚您希望所有这些在语言上如何工作。 'Krąków'和'Kraków'是同一个地方吗? 'Ąaron'和'Aaron'是同一个人吗?如果是这样,你想要utf8_general_ci。

您可以考虑更改您显示的表格,如下所示:

  ALTER TABLE Cities
MODIFY COLUMN city_Name 
              VARCHAR(145)
              CHARACTER SET utf8 
              COLLATE utf8_general_ci

这将按照您希望的方式设置表格中的列。