12.8.4 表达式中的排序规则强制性
在大多数语句中,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 将 coercibility 值分配如下:
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
排序规则。这类似于混合非二进制和二进制字符串的操作,对collations而不是数据类型进行评估。
-
虽然自动转换不在SQL标准中,但是标准确实说每个字符集都是Unicode的一个“子集”。因为是众所周知的原则“对超集也可以应用于子集,”我们认为Unicode的排序规则可以用于与非Unicode字符串的比较。更广泛地说,MySQL 使用字符集词汇,可以有时用来确定字符集之间的子集关系,从而使操作中可能出现错误的操作项进行转换。见第12.2.1节,“字符集词汇”。
以下表格展示了前面规则的应用。
Comparison | Collation Used |
---|---|
column1 = 'A' |
使用column1 的排序规则 |
column1 = 'A' COLLATE x |
使用'A'的排序规则 |
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节,“表达式求值中的类型转换”。