如何在 MySQL 中控制 UTF-8 排序?

Posted

技术标签:

【中文标题】如何在 MySQL 中控制 UTF-8 排序?【英文标题】:How can I control UTF-8 ordering in MySQL? 【发布时间】:2012-05-13 21:03:42 【问题描述】:

例如,这是标准“按名称排序”查询返回的顺序:

name
------
Cebbb
Čebbc
Cebbd

我想按名称排序并得到重音字符first,与其他重音字符分组,例如

name
------
Čebbc
Cebbb
Cebbd

默认情况下,mysqlČ 视为C,以进行排序,并按显示的顺序进行排序。

或者,在 php 中是否有一种方法可以将Č“转换”为C,以便进行比较?

【问题讨论】:

【参考方案1】:

你可以add a COLLATE expression to your ORDER BY clause:

SELECT k
FROM t1
ORDER BY k COLLATE utf8_spanish_ci;

然后,将使用正确的排序规则对列进行排序,并且列定义可以保持不变。

【讨论】:

我认为最初的问题令人困惑;我已经更新澄清。 Yogu 的解决方案似乎可以回答您的问题。使用正确的排序规则,SQL 将按照该语言的正确顺序对字符进行排序。【参考方案2】:

最简单的方法是对列本身应用适当的排序规则,例如:

CREATE TABLE foo (
    foo_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(30) NOT NULL COLLATE 'utf8_spanish_ci',
    PRIMARY KEY (`foo_id`)
)
COLLATE='utf8_spanish_ci'
ENGINE=InnoDB;

更新:

Č 不是西班牙字母:

在克罗地亚语、斯洛文尼亚语、波斯尼亚语、Skolt Sami 和 Lakota 字母表中,它 是字母表中的第四个字母。在捷克语、北萨米语字母表中 和波罗的海语言立陶宛语和拉脱维亚语,这封信是 第五名。在斯洛伐克语中,它是字母表中的第六个字母。也是 用于普什图语(相当于 چ‎)和 Saanich。

与数字不同,字母没有固定的绝对顺序。字母顺序的整个概念是相对的——你必须首先选择一个规则集。运行此 SQL 查询以了解您的 MySQL 服务器中有哪些可用:

SHOW CHARACTER SET

...并选择更符合您期望的那个。手册中有brief description。

【讨论】:

当您说“正确”时,是否包括 utf8_general_ci?这就是表和列已经指定的内容,并且更改它不会非常容易,因为数据库不是“我的”(它是 joomla 提供的) “正确”取决于语言。排序文本时有不同的规则。如果utf8_spanish_ci 是您当前的排序规则,那么您的确切问题是什么?你不想要现代西班牙规则,或者你没有得到它们? 啊——我明白了。你是说Č是西班牙文吗?在这种情况下,它实际上不是(或没有在西班牙语中使用),但是 - 我希望 - 这不相关。将会有来自多种语言的一大堆字符。如果尝试将 Č 视为 C 是荒谬的,那么我很高兴 not 这样做,但这又回到了 MySQL 将它们视为平等的原始问题。跨度> @BobbyJack 然后使用utf8_bin。它通过 Unicode 代码点比较字符,这意味着没有重音或大小写折叠。【参考方案3】:

要将带有重音或变音符号的特殊字符替换为普通的拉丁字符,可以使用php函数iconv

iconv("UTF-8", "ASCII//TRANSLIT", $text)

这会将变量$text 转换为纯ASCII 字符。例如,müßig 会被转换成 muessig,而 caffée 会被转换成 caffee

【讨论】:

虽然我不知道 alternative 解决方案与您的主要问题有什么关系 另一种解决方案允许我在 PHP 中将这两个字符视为相同,从而使我能够将它们分组到一个公共标题下。我从数据库中获取行,然后在初始字符更改时输出“标题” - 就像书中的索引列表一样。目前,我得到一个“C”名称列表,后跟一个“Č”名称,然后是另一个“C”名称列表。 嗯,好吧,那么 php 解决方案似乎更好,因为您肯定不希望每个特殊字符都有一个部分。 这绝对是最接近的解决方案。由于本地环境问题(即 iconv 和 MAMP 的问题),我实际上无法立即使用此解决方案,但 iconv() 绝对解决了比较问题。 MySql SORT BY 修复会更好,但与此同时我会投票给你。 特殊字符是例外,因此每个特殊字符的部分实际上是可以的。【参考方案4】:

好的,这是我的解决方案,诚然,这是一个非常特殊的情况:

ORDER BY SUBSTRING(name, 1, 1),
         BINARY SUBSTRING(name, 1, 1),
         name

这当然不是最有效的查询——不过,在这种情况下,这并不是什么大问题——但它确实通过以下方式解决了我的问题:

    按初始字符排序(MySql 会将ČC 视为相同) 然后 按初始字符的二进制值排序,这将区分ČC 然后按全名排序,这实际上将按字符串的其余部分排序。

这将在第一个字符之后进行非最佳排序,但这不是问题。

【讨论】:

以上是关于如何在 MySQL 中控制 UTF-8 排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何将整个 MySQL 数据库字符集和排序规则转换为 UTF-8?

如何在 MySQL 排序中控制 nulls-first 或 nulls-last?

java如何实现mysql数据库有中文字段中文排序

PostgreSQL UTF-8 二进制排序规则

如何指定 sqlite 数据库排序规则

如何在Windows控制台中显示utf-8