在绝大多数语句中,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 使用字符集库的概念,它有时可以用来确定字符集之间的子集关系,并允许转换会导致错误的操作中的操作数。请参阅第 12.2.1 节,“字符集库”。
下表说明了上述规则的一些应用。
比较 | 使用的排序规则 |
---|---|
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 节,“表达式求值中的类型转换”。