在大多数语句中,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 节,“表达式求值中的类型转换”。