【问题标题】:How to setup MySQL to handle unicode diacriticals properly?如何设置 MySQL 以正确处理 unicode 变音符号?
【发布时间】:2013-01-31 22:07:30
【问题描述】:

这是一个奇怪的谜题,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 `Cities` (
  `city_Name` VARCHAR(145) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`city_Name`)
) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

请注意,我不能为列设置 不同 utf8_bin,因为整个表都是 utf8_bin,所以实际上列的排序规则被重置为默认值。

【问题讨论】:

  • 这是设计使然。您不会失去重音,只是在比较它们时非常宽容。等等,找个骗子....
  • 好吧,我找不到好的副本,我懒得翻遍 10 页。一般的答案是,您需要使用utf8_bin 排序规则进行重音和区分大小写的比较,或者作为表的排序规则,或者在比较时使用COLLATE utf8_bin;。我不确定这是否是这个问题的最终决定,或者是否有对口音敏感的国家排序规则,但这就是所有答案所暗示的。
  • @Pekka웃,我为整个表设置了 utf8_bin,现在我还为特定列设置了 utf8_bin。然而,对于 MySQL,“a”仍然是“±”。 更新:实际上没有区别,因为如果有人对列使用默认值,则更改整个表排序规则也会更改列排序规则。
  • 您可以在列规范本身中指定排序规则,例如columnname VARCHAR(100) CHARSET utf8 COLLATE utf8_bin NOT NULLDEFAULT 设置是在创建时获取的,但在创建列后更改它不会执行任何操作。使用SHOW CREATE TABLE tablename 查看现有列的字符集/排序规则。

标签: mysql unicode utf-8 collation diacritics


【解决方案1】:

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'

您是说“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

这将按照您想要的方式设置表格中的列。

【讨论】:

    【解决方案2】:

    解决方案的所有功劳都归于 bobince,所以请对我的问题发表评论。

    这个问题的解决方法有点奇怪,我会冒着说 MySQL 在这方面坏了的风险。

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

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

    因此,您必须摆脱列的默认值,使其超出排序规则“family”范围的某个外来值(如果“utf8xxx”表示没有其他“utf8xxx”)。一旦摆脱它,并且您在列排序规则中看到没有说“默认”的条目,您可以设置 utf8_bin,它现在评估为默认值,但由于我们来自非默认排序规则,所以一切都按预期进行。

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

    【讨论】:

      猜你喜欢
      • 2021-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多