在大多数语句中,MySQL 使用的排序是明显的。例如,在以下情况下,应该很清楚排序是列 x
的排序:
SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;
然而,在多个操作数的情况下,可能存在歧义。例如,以下语句比较列 x
和字符串文字 'Y'
:
SELECT x FROM T WHERE x = 'Y';
如果 x
和 'Y'
具有相同的排序,那么比较操作的排序无歧义。但是,如果它们具有不同的排序,应该使用 x
的排序还是 'Y'
的排序? x
和 'Y'
都具有排序,因此哪个排序优先?
在其他上下文中也可能出现排序的混杂,例如,多参数连接操作,如 CONCAT(x,'Y')
,将其参数组合成一个字符串。结果应该具有什么排序?
为了解决这些问题,MySQL 检查一个项目的排序是否可以强制转换为另一个项目的排序。MySQL 将强制性值分配如下:
MySQL 使用强制性值和以下规则来解决歧义:
-
使用强制性值最低的排序。
-
如果两侧具有相同的强制性值,则:
-
如果两侧都是 Unicode 或两侧都不是 Unicode,则是错误。
-
如果一侧具有 Unicode 字符集,而另一侧具有非 Unicode 字符集,则 Unicode 字符集侧胜出,并对非 Unicode 侧应用自动字符集转换。例如,以下语句不会返回错误:
SELECT CONCAT(utf8mb4_column, latin1_column) FROM t1;
它返回一个结果,该结果具有字符集
utf8mb4
,并且具有与utf8mb4_column
相同的排序规则。latin1_column
的值在连接之前自动转换为utf8mb4
。 -
对于来自同一字符集但混合了
_bin
排序规则和_ci
或_cs
排序规则的操作,使用_bin
排序规则。这类似于如何将非二进制字符串和二进制字符串作为二进制字符串进行操作,应用于排序规则而不是数据类型。
-
尽管自动转换不在SQL标准中,但标准说每个字符集(在支持的字符方面)是 Unicode 的一个“子集”。因为“什么适用于超集也适用于子集”,我们认为 Unicode 排序规则可以应用于与非 Unicode 字符串的比较。更一般地说,MySQL 使用字符集repertoire 概念,可以有时用于确定字符集之间的子集关系并启用操作数的转换,以避免错误。见第 12.2.1 节,“字符集repertoire”。
以下表格说明了前述规则的一些应用。
Comparison | Collation Used |
---|---|
column1 = 'A' | 使用column1的排序规则 |
column1 = 'A' COLLATE x | 使用'A' COLLATE x的排序规则 |
column1 COLLATE x = 'A' COLLATE y | 错误 |
要确定字符串表达式的可强制性,请使用COERCIBILITY()
函数(见第 14.15 节,“信息函数”):
mysql> SELECT COERCIBILITY(_utf8mb4'A' COLLATE utf8mb4_bin);
-> 0
mysql> SELECT COERCIBILITY(VERSION());
-> 3
mysql> SELECT COERCIBILITY('A');
-> 4
mysql> SELECT COERCIBILITY(1000);
-> 5
mysql> SELECT COERCIBILITY(NULL);
-> 6
对于数字或时间值到字符串的隐式转换,例如在表达式CONCAT(1, 'abc')
中对参数1
的转换,结果是一个字符(非二进制)字符串,该字符串具有由character_set_connection
和collation_connection
系统变量确定的字符集和排序规则。见第 14.3 节,“表达式评估中的类型转换”。