10.8.4 table 达式中的排序规则强制性

在绝大多数语句中,很明显 MySQL 使用什么排序规则来解决比较操作。例如,在以下情况下,应该清楚排序规则是x列的排序规则:

SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;

但是,对于多个操作数,可能会有歧义。例如,此语句在列x和字符串 Literals'Y'之间进行比较:

SELECT x FROM T WHERE x = 'Y';

如果x'Y'具有相同的排序规则,则对于用于比较的排序规则没有歧义。但是,如果它们具有不同的排序规则,则比较应使用x还是'Y'的排序规则? x'Y'都有排序规则,那么哪个排序规则优先?

排序规则的混合也可能在比较之外的其他情况下发生。例如,诸如CONCAT(x,'Y')之类的多参数串联操作将其参数组合以产生单个字符串。结果应具有什么排序规则?

为了解决这些问题,MySQL 检查是否可以将一项的排序规则强制为另一项的排序规则。 MySQL 分配强制性值如下:

  • 显式的COLLATE子句的强制性为 0(根本不可强制)。

  • 具有不同排序规则的两个字符串的串联的强制性为 1.

  • 列或存储的例程参数或局部变量的排序规则的强制性为 2.

  • “系统常数”(由USER()VERSION()之类的函数返回的字符串)的强制性为 3.

  • Literals 的排序规则的强制性为 4.

  • 数字或时间值的排序规则的强制性为 5.

  • NULL或从NULL派生的 table 达式的矫顽力为 6.

MySQL 使用强制性值和以下规则来解决歧义:

  • 使用具有最低矫顽力值的排序规则。

  • 如果双方具有相同的强制性,则:

  • 如果双方都是 Unicode,或者双方都不是 Unicode,则错误。

    • 如果其中一方具有 Unicode 字符集,而另一方具有非 Unicode 字符集,则具有 Unicode 字符集的一方获胜,并且自动字符集转换将应用于非 Unicode 一方。例如,以下语句不返回错误:
SELECT CONCAT(utf8_column, latin1_column) FROM t1;

它返回一个字符集为utf8且排序规则与utf8_column相同的结果。串联之前,latin1_column的值会自动转换为utf8

  • 对于具有相同字符集但混合了_bin归类和_ci_cs归类的操作数的操作,将使用_bin归类。这类似于将非二进制和二进制字符串混合在一起的操作如何将操作数评估为二进制字符串(应用于排序规则而不是数据类型)。

尽管自动转换不在 SQL 标准中,但该标准确实指出,每个字符集(就支持的字符而言)都是 Unicode 的“子集”。因为众所周知的原则是“适用于超集的内容可以适用于子集”,所以我们认为 Unicode 的排序规则可以适用于与非 Unicode 字符串的比较。更一般而言,MySQL 使用字符集库的概念,该概念有时可用于确定字符集之间的子集关系,并实现操作数的转换,否则将产生错误。参见第 10.2.1 节“字符集库”

下 table 说明了上述规则的某些应用。

ComparisonCollation Used
column1 = 'A'使用排序规则column1
column1 = 'A' COLLATE x使用排序规则'A' COLLATE x
column1 COLLATE x = 'A' COLLATE yError

要确定字符串 table 达式的可强制性,请使用COERCIBILITY()函数(请参见第 12.15 节“信息功能”):

mysql> SELECT COERCIBILITY(_utf8'A' COLLATE utf8_bin);
        -> 0
mysql> SELECT COERCIBILITY(VERSION());
        -> 3
mysql> SELECT COERCIBILITY('A');
        -> 4
mysql> SELECT COERCIBILITY(1000);
        -> 5
mysql> SELECT COERCIBILITY(NULL);
        -> 6

对于将数值或时间值隐式转换为字符串(例如在 table 达式CONCAT(1, 'abc')中的自变量1发生的情况),结果是一个字符(非二进制)字符串,该字符串具有由character_set_connectioncollation_connection系统变量确定的字符集和排序规则。参见第 12.2 节“table 达式评估中的类型转换”