字符集的范围是指该字符集中包含的字符集合。
字符串表达式具有范围属性,该属性可以有两个值:
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
范围。第一个参数对结果范围没有影响,即使表达式使用字符串值也是如此。