字符集的指令表是该字符集中字符的集合。
字符串表达式具有指令表属性,该属性可以有两个值:
ASCII
:表达式只能包含 ASCII 字符;也就是说,Unicode 范围U+0000
到U+007F
中的字符。UNICODE
:表达式可以包含 Unicode 范围U+0000
到U+10FFFF
中的字符。这包括基本多语言平面 (BMP) 范围 (U+0000
到U+FFFF
) 中的字符和 BMP 范围外的补充字符 (U+10000
到U+10FFFF
)。
ASCII
范围是 UNICODE
范围的子集,因此具有 ASCII
指令表的字符串可以安全地转换为具有 UNICODE
指令表的任何字符串的字符集,而不会丢失信息。它也可以安全地转换为 ascii
字符集的任何超集。(所有 MySQL 字符集都是 ascii
的超集,但 swe7
除外,它将一些标点字符重新用于瑞典语重音字符。)
在许多情况下,指令表的使用可以在表达式中进行字符集转换,否则 MySQL 会在排序规则强制性规则不足以解决歧义时返回 “排序规则混合非法” 错误。(有关强制性的信息,请参阅 第 12.8.4 节“表达式中的排序规则强制性”。)
以下讨论提供了表达式及其指令表的示例,并描述了指令表的使用如何改变字符串表达式求值:
字符串常量的指令表取决于字符串内容,并且可能与字符串字符集的指令表不同。请考虑以下语句:
SET NAMES utf8mb4; SELECT 'abc'; SELECT _utf8mb4'def';
尽管在上述每种情况下字符集都是
utf8mb4
,但字符串实际上并不包含 ASCII 范围外的任何字符,因此它们的指令表是ASCII
而不是UNICODE
。具有
ascii
字符集的列由于其字符集而具有ASCII
指令表。在下表中,c1
具有ASCII
指令表:CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET ascii);
以下示例说明了在没有指令表的情况下发生错误时,指令表如何能够确定结果:
CREATE TABLE t1 ( c1 CHAR(1) CHARACTER SET latin1, c2 CHAR(1) CHARACTER SET ascii ); INSERT INTO t1 VALUES ('a','b'); SELECT CONCAT(c1,c2) FROM t1;
如果没有指令表,则会发生此错误:
ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (ascii_general_ci,IMPLICIT) for operation 'concat'
使用指令表,可以进行子集到超集(
ascii
到latin1
)转换,并返回结果:+---------------+ | CONCAT(c1,c2) | +---------------+ | ab | +---------------+
具有一个字符串参数的函数继承其参数的指令表。
UPPER(_utf8mb4'abc')
的结果具有ASCII
指令表,因为其参数具有ASCII
指令表。(尽管有_utf8mb4
引导符,但字符串'abc'
不包含 ASCII 范围外的任何字符。)对于返回字符串但不具有字符串参数并使用
character_set_connection
作为结果字符集的函数,如果character_set_connection
为ascii
,则结果指令表为ASCII
,否则为UNICODE
:FORMAT(numeric_column, 4);
指令表的使用改变了 MySQL 对以下示例的求值方式:
SET NAMES ascii; CREATE TABLE t1 (a INT, b VARCHAR(10) CHARACTER SET latin1); INSERT INTO t1 VALUES (1,'b'); SELECT CONCAT(FORMAT(a, 4), b) FROM t1;
如果没有指令表,则会发生此错误:
ERROR 1267 (HY000): Illegal mix of collations (ascii_general_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation 'concat'
使用指令表,会返回结果:
+-------------------------+ | CONCAT(FORMAT(a, 4), b) | +-------------------------+ | 1.0000b | +-------------------------+
具有两个或多个字符串参数的函数对结果指令表使用 “最宽” 参数指令表,其中
UNICODE
比ASCII
宽。请考虑以下CONCAT()
调用:CONCAT(_ucs2 X'0041', _ucs2 X'0042') CONCAT(_ucs2 X'0041', _ucs2 X'00C2')
对于第一个调用,指令表是
ASCII
,因为两个参数都在 ASCII 范围内。对于第二个调用,指令表是UNICODE
,因为第二个参数在 ASCII 范围之外。函数返回值的指令表是根据仅影响结果字符集和排序规则的那些参数的指令表确定的。
IF(column1 < column2, 'smaller', 'greater')
结果指令表是
ASCII
,因为两个字符串参数(第二个参数和第三个参数)都具有ASCII
指令表。第一个参数对结果指令表无关紧要,即使表达式使用字符串值也是如此。