MySQL8 中文参考(十九)
11.4 用户定义变量
您可以在一个语句中将值存储在用户定义变量中,并在另一个语句中引用它。这使您可以从一个语句传递值到另一个语句。
用户变量写作@*
var_name*
,其中变量名var_name
由字母数字字符、.
、_
和$
组成。如果要包含其他字符,可以将其引用为字符串或标识符(例如,@'my-var'
、@"my-var"
或@
my-var``)。
用户定义变量是会话特定的。一个客户端定义的用户变量对其他客户端不可见或不可用。(例外:具有对性能模式user_variables_by_thread
表的访问权限的用户可以看到所有会话的所有用户变量。)给定客户端会话的所有变量在该客户端退出时会自动释放。
用户变量名称不区分大小写。名称最大长度为 64 个字符。
设置用户定义变量的一种方法是发出SET
语句:
SET @*var_name* = *expr* [, @*var_name* = *expr*] ...
对于SET
,赋值操作符可以使用=
或:=
。
用户变量可以被赋予整数、小数、浮点、二进制或非二进制字符串、或NULL
值等有限数据类型的值。赋予小数和实数值不会保留值的精度或标度。除了允许的类型之外的类型的值会被转换为允许的类型。例如,具有时间或空间数据类型的值会被转换为二进制字符串。具有JSON
数据类型的值会被转换为具有utf8mb4
字符集和utf8mb4_bin
校对的字符串。
如果用户变量被赋予非二进制(字符)字符串值,则具有与字符串相同的字符集和校对。用户变量的可强制性是隐式的。(这与表列值的可强制性相同。)
赋予用户变量的十六进制或位值被视为二进制字符串。要将十六进制或位值作为数字赋予用户变量,需在数值上下文中使用。例如,添加 0 或使用CAST(... AS UNSIGNED)
:
mysql> SET @v1 = X'41';
mysql> SET @v2 = X'41'+0;
mysql> SET @v3 = CAST(X'41' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1 | @v2 | @v3 |
+------+------+------+
| A | 65 | 65 |
+------+------+------+
mysql> SET @v1 = b'1000001';
mysql> SET @v2 = b'1000001'+0;
mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1 | @v2 | @v3 |
+------+------+------+
| A | 65 | 65 |
+------+------+------+
如果用户变量的值在结果集中被选中,则作为字符串返回给客户端。
如果引用未初始化的变量,则其值为NULL
,类型为字符串。
从 MySQL 8.0.22 开始,在准备语句中引用用户变量时,其类型在首次准备语句时确定,并在此后每次执行语句时保留此类型。类似地,在存储过程中的语句中使用的用户变量的类型在首次调用存储过程时确定,并在每次后续调用时保留此类型。
用户变量可以在大多数允许表达式的上下文中使用。目前不包括明确要求字面值的上下文,例如SELECT
语句的LIMIT
子句,或LOAD DATA
语句的IGNORE *
N* LINES
子句。
MySQL 的先前版本允许在SET
之外的语句中为用户变量赋值。这种功能在 MySQL 8.0 中得到支持以保持向后兼容性,但可能在将来的 MySQL 版本中被移除。
在这种方式进行赋值时,必须使用:=
作为赋值运算符;=
在SET
之外的语句中被视为比较运算符。
表达式中涉及用户变量的评估顺序是未定义的。例如,不能保证SELECT @a, @a:=@a+1
首先评估@a
然后执行赋值。
此外,变量的默认结果类型基于语句开始时的类型。如果变量在语句开始时保存一个类型的值,并在其中分配一个不同类型的新值,则可能会产生意外效果。
为避免此行为问题,在单个语句中不要为同一变量分配值并读取该值,或者在使用之前将变量设置为0
、0.0
或''
以定义其类型。
当在HAVING
、GROUP BY
和ORDER BY
中引用在选择表达式列表中分配值的变量时,不会按预期工作,因为表达式在客户端上评估,因此可能使用来自先前行的过时列值。
用户变量旨在提供数据值。它们不能直接用作 SQL 语句中的标识符或标识符的一部分,例如在期望表或数据库名称的上下文中,或作为保留字,比如SELECT
。即使变量被引用,也是如此,如下例所示:
mysql> SELECT c1 FROM t;
+----+
| c1 |
+----+
| 0 |
+----+
| 1 |
+----+
2 rows in set (0.00 sec)
mysql> SET @col = "c1";
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @col FROM t;
+------+
| @col |
+------+
| c1 |
+------+
1 row in set (0.00 sec)
mysql> SELECT `@col` FROM t;
ERROR 1054 (42S22): Unknown column '@col' in 'field list'
mysql> SET @col = "`c1`";
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @col FROM t;
+------+
| @col |
+------+
| `c1` |
+------+
1 row in set (0.00 sec)
不能使用用户变量提供标识符的原则有一个例外,那就是当您构建一个字符串以供稍后执行的准备语句时。在这种情况下,用户变量可以用来提供语句的任何部分。以下示例说明了如何实现这一点:
mysql> SET @c = "c1";
Query OK, 0 rows affected (0.00 sec)
mysql> SET @s = CONCAT("SELECT ", @c, " FROM t");
Query OK, 0 rows affected (0.00 sec)
mysql> PREPARE stmt FROM @s;
Query OK, 0 rows affected (0.04 sec)
Statement prepared
mysql> EXECUTE stmt;
+----+
| c1 |
+----+
| 0 |
+----+
| 1 |
+----+
2 rows in set (0.00 sec)
mysql> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
更多信息请参见第 15.5 节,“准备语句”。
类似的技术可以在应用程序中使用,以使用程序变量构建 SQL 语句,如下所示使用 PHP 5:
<?php
$mysqli = new mysqli("localhost", "user", "pass", "test");
if( mysqli_connect_errno() )
die("Connection failed: %s\n", mysqli_connect_error());
$col = "c1";
$query = "SELECT $col FROM t";
$result = $mysqli->query($query);
while($row = $result->fetch_assoc())
{
echo "<p>" . $row["$col"] . "</p>\n";
}
$result->close();
$mysqli->close();
?>
以这种方式组装 SQL 语句有时被称为“动态 SQL”。
11.5 表达式
此部分列出了在 MySQL 中表达式必须遵循的语法规则,并提供了关于可能出现在表达式中的术语类型的附加信息。
-
表达式语法
-
表达式术语注释
-
时间间隔
表达式语法
以下语法规则定义了 MySQL 中的表达式语法。这里显示的语法基于 MySQL 源分发中 sql/sql_yacc.yy
文件中给出的语法。有关一些表达式术语的附加信息,请参见表达式术语注释。
*expr*:
*expr* OR *expr*
| *expr* || *expr*
| *expr* XOR *expr*
| *expr* AND *expr*
| *expr* && *expr*
| NOT *expr*
| ! *expr*
| *boolean_primary* IS [NOT] {TRUE | FALSE | UNKNOWN}
| *boolean_primary*
*boolean_primary*:
*boolean_primary* IS [NOT] NULL
| *boolean_primary* <=> *predicate*
| *boolean_primary* *comparison_operator* *predicate*
| *boolean_primary* *comparison_operator* {ALL | ANY} (*subquery*)
| *predicate*
*comparison_operator*: = | >= | > | <= | < | <> | !=
*predicate*:
*bit_expr* [NOT] IN (*subquery*)
| *bit_expr* [NOT] IN (*expr* [, *expr*] ...)
| *bit_expr* [NOT] BETWEEN *bit_expr* AND *predicate*
| *bit_expr* SOUNDS LIKE *bit_expr*
| *bit_expr* [NOT] LIKE *simple_expr* [ESCAPE *simple_expr*]
| *bit_expr* [NOT] REGEXP *bit_expr*
| *bit_expr*
*bit_expr*:
*bit_expr* | *bit_expr*
| *bit_expr* & *bit_expr*
| *bit_expr* << *bit_expr*
| *bit_expr* >> *bit_expr*
| *bit_expr* + *bit_expr*
| *bit_expr* - *bit_expr*
| *bit_expr* * *bit_expr*
| *bit_expr* / *bit_expr*
| *bit_expr* DIV *bit_expr*
| *bit_expr* MOD *bit_expr*
| *bit_expr* % *bit_expr*
| *bit_expr* ^ *bit_expr*
| *bit_expr* + *interval_expr*
| *bit_expr* - *interval_expr*
| *simple_expr*
*simple_expr*:
*literal*
| *identifier*
| *function_call*
| *simple_expr* COLLATE *collation_name*
| *param_marker*
| *variable*
| *simple_expr* || *simple_expr*
| + *simple_expr*
| - *simple_expr*
| ~ *simple_expr*
| ! *simple_expr*
| BINARY *simple_expr*
| (*expr* [, *expr*] ...)
| ROW (*expr*, *expr* [, *expr*] ...)
| (*subquery*)
| EXISTS (*subquery*)
| {*identifier* *expr*}
| *match_expr*
| *case_expr*
| *interval_expr*
关于运算符优先级,请参见第 14.4.1 节,“运算符优先级”。某些运算符的优先级和含义取决于 SQL 模式:
-
默认情况下,
||
是逻辑OR
运算符。启用PIPES_AS_CONCAT
后,||
是字符串连接运算符,优先级介于^
和一元运算符之间。 -
默认情况下,
!
的优先级高于NOT
。启用HIGH_NOT_PRECEDENCE
后,!
和NOT
具有相同的优先级。
请参见第 7.1.11 节,“服务器 SQL 模式”。
表达式术语注释
有关文字值语法,请参见第 11.1 节,“文字值”。
有关标识符语法,请参见第 11.2 节,“模式对象名称”。
变量可以是用户变量、系统变量、存储过程本地变量或参数:
-
用户变量:第 11.4 节,“用户定义变量”
-
系统变量:第 7.1.9 节,“使用系统变量”
-
存储过程本地变量:第 15.6.4.1 节,“本地变量 DECLARE 语句”
-
存储过程参数:第 15.1.17 节,“CREATE PROCEDURE 和 CREATE FUNCTION 语句”
param_marker
是用于占位符的预处理语句中使用的 ?
。请参见第 15.5.1 节,“PREPARE 语句”。
(*
subquery*)
表示返回单个值的子查询;即标量子查询。参见 Section 15.2.15.1, “标量操作数的子查询”。
{*
identifier* *
expr*}
是 ODBC 转义语法,为了兼容 ODBC 而被接受。值为 expr
。语法中的 {
和 }
大括号应该按照字面意义书写;它们不是在其他语法描述中使用的元语法。
match_expr
表示一个 MATCH
表达式。参见 Section 14.9, “全文搜索函数”。
case_expr
表示一个 CASE
表达式。参见 Section 14.5, “流程控制函数”。
interval_expr
表示一个时间间隔。参见 时间间隔。
时间间隔
interval_expr
在表达式中表示一个时间间隔。间隔具有以下语法:
INTERVAL *expr* *unit*
expr
代表一个数量。unit
代表用于解释数量的单位;它是一个类似于 小时
, 天
或 周
的指定符号。INTERVAL
关键字和 unit
指定符号不区分大小写。
以下表格显示了每个 unit
值的 expr
参数的预期形式。
表 11.2 时间间隔表达式和单位参数
unit 值 |
预期的 expr 格式 |
---|---|
MICROSECOND |
微秒 |
SECOND |
秒 |
MINUTE |
分钟 |
HOUR |
小时 |
DAY |
天 |
WEEK |
周 |
MONTH |
月 |
QUARTER |
季度 |
YEAR |
年 |
SECOND_MICROSECOND |
'秒.微秒' |
MINUTE_MICROSECOND |
'分钟:秒.微秒' |
MINUTE_SECOND |
'分钟:秒' |
HOUR_MICROSECOND |
'小时:分钟:秒.微秒' |
HOUR_SECOND |
'小时:分钟:秒' |
HOUR_MINUTE |
'小时:分钟' |
DAY_MICROSECOND |
'天 小时:分钟:秒.微秒' |
DAY_SECOND |
'天 小时:分钟:秒' |
DAY_MINUTE |
'天 小时:分钟' |
DAY_HOUR |
'天 小时' |
YEAR_MONTH |
'年-月' |
unit 值 |
预期的 expr 格式 |
MySQL 允许在 expr
格式中使用任何标点符号分隔符。表中显示的是建议的分隔符。
时间间隔用于某些函数,例如 DATE_ADD()
和 DATE_SUB()
:
mysql> SELECT DATE_ADD('2018-05-01',INTERVAL 1 DAY);
-> '2018-05-02'
mysql> SELECT DATE_SUB('2018-05-01',INTERVAL 1 YEAR);
-> '2017-05-01'
mysql> SELECT DATE_ADD('2020-12-31 23:59:59',
-> INTERVAL 1 SECOND);
-> '2021-01-01 00:00:00'
mysql> SELECT DATE_ADD('2018-12-31 23:59:59',
-> INTERVAL 1 DAY);
-> '2019-01-01 23:59:59'
mysql> SELECT DATE_ADD('2100-12-31 23:59:59',
-> INTERVAL '1:1' MINUTE_SECOND);
-> '2101-01-01 00:01:00'
mysql> SELECT DATE_SUB('2025-01-01 00:00:00',
-> INTERVAL '1 1:1:1' DAY_SECOND);
-> '2024-12-30 22:58:59'
mysql> SELECT DATE_ADD('1900-01-01 00:00:00',
-> INTERVAL '-1 10' DAY_HOUR);
-> '1899-12-30 14:00:00'
mysql> SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);
-> '1997-12-02'
mysql> SELECT DATE_ADD('1992-12-31 23:59:59.000002',
-> INTERVAL '1.999999' SECOND_MICROSECOND);
-> '1993-01-01 00:00:01.000001'
也可以使用 INTERVAL
与 +
或 -
运算符在表达式中执行时间算术:
date + INTERVAL *expr* *unit*
date - INTERVAL *expr* *unit*
如果另一侧的表达式是日期或日期时间值,则+
运算符的两侧都允许INTERVAL *
expr* *
unit*
。对于-
运算符,只允许在右侧使用INTERVAL *
expr* *
unit`*,因为从间隔中减去日期或日期时间值是没有意义的。
mysql> SELECT '2018-12-31 23:59:59' + INTERVAL 1 SECOND;
-> '2019-01-01 00:00:00'
mysql> SELECT INTERVAL 1 DAY + '2018-12-31';
-> '2019-01-01'
mysql> SELECT '2025-01-01' - INTERVAL 1 SECOND;
-> '2024-12-31 23:59:59'
EXTRACT()
函数使用与DATE_ADD()
或DATE_SUB()
相同类型的unit
指示符,但是从日期中提取部分而不是执行日期算术:
mysql> SELECT EXTRACT(YEAR FROM '2019-07-02');
-> 2019
mysql> SELECT EXTRACT(YEAR_MONTH FROM '2019-07-02 01:02:03');
-> 201907
时间间隔可以在CREATE EVENT
语句中使用:
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
UPDATE myschema.mytable SET mycol = mycol + 1;
如果您指定的间隔值太短(不包括从unit
关键字中预期的所有间隔部分),MySQL 会假定您省略了间隔值的最左边部分。例如,如果您指定了DAY_SECOND
作为unit
,则expr
的值应包含天、小时、分钟和秒部分。如果您指定类似 '1:10'
的值,MySQL 会假定缺少天数和小时数部分,该值表示分钟和秒数。换句话说,'1:10' DAY_SECOND
被解释为等同于'1:10' MINUTE_SECOND
。这类似于 MySQL 解释TIME
值表示经过的时间而不是一天中的时间。
expr
被视为字符串,因此如果您在INTERVAL
中指定非字符串值,请小心。例如,使用HOUR_MINUTE
的间隔符号,'6/4'被视为 6 小时 4 分钟,而6/4
计算结果为1.5000
,被视为 1 小时 5000 分钟:
mysql> SELECT '6/4', 6/4;
-> 1.5000
mysql> SELECT DATE_ADD('2019-01-01', INTERVAL '6/4' HOUR_MINUTE);
-> '2019-01-01 06:04:00'
mysql> SELECT DATE_ADD('2019-01-01', INTERVAL 6/4 HOUR_MINUTE);
-> '2019-01-04 12:20:00'
为了确保间隔值的解释符合您的期望,可以使用CAST()
操作。将6/4
视为 1 小时 5 分钟,将其转换为具有单个小数位的DECIMAL
- DECIMAL, NUMERIC")值:
mysql> SELECT CAST(6/4 AS DECIMAL(3,1));
-> 1.5
mysql> SELECT DATE_ADD('1970-01-01 12:00:00',
-> INTERVAL CAST(6/4 AS DECIMAL(3,1)) HOUR_MINUTE);
-> '1970-01-01 13:05:00'
如果您向日期值添加或减去包含时间部分的内容,则结果会自动转换为日期时间值:
mysql> SELECT DATE_ADD('2023-01-01', INTERVAL 1 DAY);
-> '2023-01-02'
mysql> SELECT DATE_ADD('2023-01-01', INTERVAL 1 HOUR);
-> '2023-01-01 01:00:00'
如果您添加MONTH
、YEAR_MONTH
或YEAR
,并且结果日期的天数大于新月份的最大天数,则天数会调整为新月份的最大天数:
mysql> SELECT DATE_ADD('2019-01-30', INTERVAL 1 MONTH);
-> '2019-02-28'
日期算术运算需要完整的日期,不适用于不完整的日期,如'2016-07-00'
或格式错误的日期:
mysql> SELECT DATE_ADD('2016-07-00', INTERVAL 1 DAY);
-> NULL
mysql> SELECT '2005-03-32' + INTERVAL 1 MONTH;
-> NULL
11.6 查询属性
SQL 语句最显著的部分是语句的文本。从 MySQL 8.0.23 开始,客户端还可以定义适用于发送到服务器执行的下一个语句的查询属性:
-
在发送语句之前定义属性。
-
属性存在直到语句执行结束,此时属性集被清除。
-
在属性存在期间,它们可以在服务器端访问。
查询属性可能被用于的示例方式:
-
一个 Web 应用程序生成页面,生成数据库查询,并且对于每个查询必须跟踪生成它的页面的 URL。
-
应用程序在每个查询中传递额外的处理信息,供插件(如审计插件或查询重写插件)使用。
MySQL 支持这些功能,无需使用诸如在查询字符串中包含特殊格式的注释之类的变通方法。本节的其余部分描述了如何使用查询属性支持,包括必须满足的先决条件。
-
定义和访问查询属性
-
使用查询属性的先决条件
-
查询属性可加载函数
定义和访问查询属性
使用 MySQL C API 的应用程序通过调用mysql_bind_param()
函数定义查询属性。参见 mysql_bind_param()。其他 MySQL 连接器也可能提供查询属性支持。请参阅各个连接器的文档。
mysql客户端具有query_attributes
命令,可以定义最多 32 对属性名称和值。参见 Section 6.5.1.2, “mysql 客户端命令”。
查询属性名称使用由character_set_client
系统变量指示的字符集传输。
要在已定义属性的 SQL 语句中访问查询属性,请按照使用查询属性的先决条件中描述的方式安装query_attributes
组件。该组件实现了一个mysql_query_attribute_string()
可加载函数,该函数接受属性名称参数并将属性值作为字符串返回,如果属性不存在,则返回NULL
。参见查询属性可加载函数。
以下示例使用mysql客户端的query_attributes
命令来定义属性名称/值对,并使用mysql_query_attribute_string()
函数通过名称访问属性值。
此示例定义了两个名为n1
和n2
的属性。第一个SELECT
显示了如何检索这些属性,并演示了检索不存在属性(n3
)会返回NULL
。第二个SELECT
显示了属性在语句之间不会持久存在。
mysql> query_attributes n1 v1 n2 v2;
mysql> SELECT
mysql_query_attribute_string('n1') AS 'attr 1',
mysql_query_attribute_string('n2') AS 'attr 2',
mysql_query_attribute_string('n3') AS 'attr 3';
+--------+--------+--------+
| attr 1 | attr 2 | attr 3 |
+--------+--------+--------+
| v1 | v2 | NULL |
+--------+--------+--------+
mysql> SELECT
mysql_query_attribute_string('n1') AS 'attr 1',
mysql_query_attribute_string('n2') AS 'attr 2';
+--------+--------+
| attr 1 | attr 2 |
+--------+--------+
| NULL | NULL |
+--------+--------+
如第二个SELECT
语句所示,在给定语句之前定义的属性仅对该语句可用,并在语句执行后被清除。要在多个语句中使用属性值,请将其分配给变量。以下示例显示了如何执行此操作,并说明了属性值通过变量在后续语句中可用,但不能通过调用mysql_query_attribute_string()
来获取:
mysql> query_attributes n1 v1 n2 v2;
mysql> SET
@attr1 = mysql_query_attribute_string('n1'),
@attr2 = mysql_query_attribute_string('n2');
mysql> SELECT
@attr1, mysql_query_attribute_string('n1') AS 'attr 1',
@attr2, mysql_query_attribute_string('n2') AS 'attr 2';
+--------+--------+--------+--------+
| @attr1 | attr 1 | @attr2 | attr 2 |
+--------+--------+--------+--------+
| v1 | NULL | v2 | NULL |
+--------+--------+--------+--------+
属性也可以通过将它们存储在表中以供以后使用:
mysql> CREATE TABLE t1 (c1 CHAR(20), c2 CHAR(20));
mysql> query_attributes n1 v1 n2 v2;
mysql> INSERT INTO t1 (c1, c2) VALUES(
mysql_query_attribute_string('n1'),
mysql_query_attribute_string('n2')
);
mysql> SELECT * FROM t1;
+------+------+
| c1 | c2 |
+------+------+
| v1 | v2 |
+------+------+
查询属性受到这些限制和限制:
-
如果在将语句发送到服务器执行之前发生多个属性定义操作,则最近的定义操作适用并替换了之前操作中定义的属性。
-
如果使用相同名称定义了多个属性,则尝试检索属性值会产生未定义的结果。
-
使用空名称定义的属性无法通过名称检索。
-
属性对使用
PREPARE
准备的语句不可用。 -
mysql_query_attribute_string()
函数不能在 DDL 语句中使用。 -
属性不会被复制。调用
mysql_query_attribute_string()
函数的语句在所有服务器上不会得到相同的值。
使用查询属性的先决条件
要在已定义属性的 SQL 语句中访问查询属性,必须安装 query_attributes
组件。请使用以下语句执行此操作:
INSTALL COMPONENT "file://component_query_attributes";
组件安装是一次性操作,不需要在每次服务器启动时执行。INSTALL COMPONENT
加载组件,并在 mysql.component
系统表中注册它,以使其在后续服务器启动期间加载。
query_attributes
组件访问查询属性以实现 mysql_query_attribute_string()
函数。参见 第 7.5.4 节,“查询属性组件”。
要卸载 query_attributes
组件,请使用以下语句:
UNINSTALL COMPONENT "file://component_query_attributes";
UNINSTALL COMPONENT
卸载组件,并从 mysql.component
系统表中注销它,以使其在后续服务器启动期间不被加载。
因为安装和卸载 query_attributes
组件会安装和卸载组件实现的 mysql_query_attribute_string()
函数,所以不需要使用 CREATE FUNCTION
或 DROP FUNCTION
来执行此操作。
查询属性可加载函数
-
mysql_query_attribute_string(*
name*)
应用程序可以定义应用于发送到服务器的下一个查询的属性。
mysql_query_attribute_string()
函数自 MySQL 8.0.23 起可用,根据属性名称返回属性值作为字符串。此函数使查询能够访问和合并适用于它的属性值。通过安装
query_attributes
组件来安装mysql_query_attribute_string()
。参见 第 11.6 节,“查询属性”,该节还讨论了查询属性的目的和用途。参数:
name
: 属性名称。
返回值:
返回成功的属性值作为字符串,如果属性不存在则返回
NULL
。示例:
以下示例使用 mysql 客户端
query_attributes
命令来定义可以被mysql_query_attribute_string()
检索的查询属性。SELECT
显示检索不存在属性(n3
)返回NULL
。mysql> query_attributes n1 v1 n2 v2; mysql> SELECT -> mysql_query_attribute_string('n1') AS 'attr 1', -> mysql_query_attribute_string('n2') AS 'attr 2', -> mysql_query_attribute_string('n3') AS 'attr 3'; +--------+--------+--------+ | attr 1 | attr 2 | attr 3 | +--------+--------+--------+ | v1 | v2 | NULL | +--------+--------+--------+
11.7 注释
MySQL 服务器支持三种注释样式:
-
从
#
字符到行尾。 -
从
--
序列到行尾。在 MySQL 中,--
(双破折号)注释样式要求第二个破折号后至少跟随一个空格或控制字符(如空格、制表符、换行符等)。这种语法与标准 SQL 注释语法略有不同,如 1.6.2.4 节,“'--'作为注释的开始”中所讨论的。 -
从
/*
序列到后续的*/
序列,就像在 C 编程语言中一样。这种语法使得注释可以跨越多行,因为开始和结束序列不需要在同一行上。
以下示例演示了所有三种注释样式:
mysql> SELECT 1+1; # This comment continues to the end of line
mysql> SELECT 1+1; -- This comment continues to the end of line
mysql> SELECT 1 /* this is an in-line comment */ + 1;
mysql> SELECT 1+
/*
this is a
multiple-line comment
*/
1;
嵌套注释不受支持,已被弃用;预计在未来的 MySQL 版本中将被移除。(在某些情况下,可能允许嵌套注释,但通常不建议使用。)
MySQL 服务器支持某些 C 风格注释的变体。这使您可以编写包含 MySQL 扩展的代码,但仍然是可移植的,通过使用以下形式的注释:
/*! *MySQL-specific code* */
在这种情况下,MySQL 服务器解析并执行注释中的代码,就像执行任何其他 SQL 语句一样,但其他 SQL 服务器应忽略这些扩展。例如,MySQL 服务器识别以下语句中的STRAIGHT_JOIN
关键字,但其他服务器不应该:
SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...
如果在!
字符后添加版本号,则仅当 MySQL 版本大于或等于指定版本号时才执行注释内的语法。以下注释中的KEY_BLOCK_SIZE
关键字仅由 MySQL 5.1.10 或更高版本的服务器执行:
CREATE TABLE t1(a INT, KEY (a)) /*!50110 KEY_BLOCK_SIZE=1024 */;
版本号使用格式Mmmrr
,其中M
是主要版本,mm
是两位数的次要版本,rr
是两位数的发布号。例如:在仅由 MySQL 服务器版本 8.0.31 或更高版本运行的语句中,使用80031
在注释中。
版本号后应跟至少一个空白字符(或注释的结尾)。从 MySQL 8.0.34 开始,如果不满足此条件,该语句将触发警告;预计这一要求将在未来的 MySQL 版本中得到严格执行。
刚才描述的注释语法适用于mysqld服务器解析 SQL 语句的方式。mysql客户端程序在将语句发送到服务器之前也会对一些语句进行解析。(它这样做是为了确定多语句输入行中的语句边界。)有关服务器和mysql客户端解析器之间的差异的信息,请参见 Section 6.5.1.6, “mysql Client Tips”。
以/*!12345 ... */
格式的注释不会存储在服务器上。如果使用此格式对存储的程序进行注释,这些注释不会保留在程序主体中。
另一种 C 风格注释语法的变体用于指定优化器提示。提示注释包括在/*
注释开头序列后跟一个+
字符。示例:
SELECT /*+ BKA(t1) */ FROM ... ;
更多信息,请参见 Section 10.9.3, “Optimizer Hints”。
在多行/* ... */
注释中使用诸如\C
之类的mysql短格式命令是不受支持的。短格式命令可以在单行/*! ... */
版本注释中工作,/*+ ... */
优化器提示注释也可以工作,这些注释存储在对象定义中。如果担心优化器提示注释可能存储在对象定义中,以至于重新加载时使用mysql
的转储文件会导致执行此类命令,要么使用--binary-mode
选项调用mysql,要么使用除mysql之外的重新加载客户端。
第十二章 字符集、排序规则、Unicode
目录
12.1 一般字符集和排序规则
12.2 MySQL 中的字符集和排序规则
12.2.1 字符集范围
12.2.2 用于元数据的 UTF-8
12.3 指定字符集和排序规则
12.3.1 排序规则命名约定
12.3.2 服务器字符集和排序规则
12.3.3 数据库字符集和排序规则
12.3.4 表的字符集和排序规则
12.3.5 列的字符集和排序规则
12.3.6 字符串文字的字符集和排序规则
12.3.7 国家字符集
12.3.8 字符集引导符
12.3.9 字符集和排序规则分配示例
12.3.10 与其他 DBMS 的兼容性
12.4 连接字符集和排序规则
12.5 配置应用程序字符集和排序规则
12.6 错误消息字符集
12.7 列字符集转换
12.8 排序规则问题
12.8.1 在 SQL 语句中使用 COLLATE
12.8.2 COLLATE 子句优先级
12.8.3 字符集和排序规则的兼容性
12.8.4 表达式中的排序规则强制性
12.8.5 二进制排序规则与 _bin 排序规则的比较
12.8.6 排序规则效果示例
12.8.7 在 INFORMATION_SCHEMA 搜索中使用排序规则
12.9 Unicode 支持
12.9.1 utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
12.9.2 utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)
12.9.3 utf8 字符集(utf8mb3 的已弃用别名)
12.9.4 ucs2 字符集(UCS-2 Unicode 编码)
12.9.5 utf16 字符集(UTF-16 Unicode 编码)
12.9.6 utf16le 字符集(UTF-16LE Unicode 编码)
12.9.7 utf32 字符集(UTF-32 Unicode 编码)
12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
12.10 支持的字符集和排序规则
12.10.1 Unicode 字符集
12.10.2 西欧字符集
12.10.3 中欧字符集
12.10.4 南欧和中东字符集
12.10.5 波罗的海字符集
12.10.6 斯拉夫字符集
12.10.7 亚洲字符集
12.10.8 二进制字符集
12.11 字符集限制
12.12 设置错误消息语言
12.13 添加字符集
12.13.1 字符定义数组
12.13.2 复杂字符集的字符串整理支持
12.13.3 复杂字符集的多字节字符支持
12.14 向字符集添加整理
12.14.1 整理实现类型
12.14.2 选择整理 ID
12.14.3 向 8 位字符集添加简单整理
12.14.4 向 Unicode 字符集添加 UCA 整理
12.15 字符集配置
12.16 MySQL 服务器区域支持
MySQL 包括字符集支持,使您能够使用各种字符集存储数据并根据各种整理进行比较。默认的 MySQL 服务器字符集和整理是utf8mb4
和utf8mb4_0900_ai_ci
,但您可以在服务器、数据库、表、列和字符串字面量级别指定字符集。
本章讨论以下主题:
-
什么是字符集和整理?
-
字符集分配的多级默认系统。
-
指定字符集和整理的语法。
-
受影响的函数和操作。
-
Unicode 支持。
-
可用的字符集和整理,附注。
-
选择错误消息的语言。
-
选择日期和月份名称的区域设置。
字符集问题不仅影响数据存储,还影响客户端程序与 MySQL 服务器之间的通信。如果希望客户端程序使用与默认字符集不同的字符集与服务器通信,需要指定。例如,要使用utf8mb4
Unicode 字符集,请在连接到服务器后发出以下语句:
SET NAMES 'utf8mb4';
有关为应用程序使用配置字符集和客户端/服务器通信中的字符集相关问题的更多信息,请参阅第 12.5 节,“配置应用程序字符集和整理”,以及第 12.4 节,“连接字符集和整理”。
12.1 一般字符集和排序规则
字符集是一组符号和编码。排序规则是一组比较字符的规则。让我们通过一个想象中的字符集的例子来明确区分。
假设我们有一个有四个字母的字母表:A
、B
、a
、b
。我们给每个字母一个数字:A
=0,B
=1,a
=2,b
=3。字母A
是一个符号,数字 0 是A
的编码,所有四个字母及其编码的组合是一个字符集。
假设我们想比较两个字符串值,A
和B
。最简单的方法是查看编码:A
为 0,B
为 1。因为 0 小于 1,我们说A
小于B
。我们刚刚对我们的字符集应用了排序规则。排序规则是一组规则(在这种情况下只有一条规则):“比较编码”。我们称这种可能的排序规则为二进制排序规则。
但是如果我们想要说小写字母和大写字母是等价的呢?那么我们至少需要两条规则:(1) 将小写字母a
和b
视为等价于A
和B
;(2) 然后比较编码。我们称之为不区分大小写的排序规则。它比二进制排序规则稍微复杂一些。
在现实生活中,大多数字符集有许多字符:不仅有A
和B
,还有整个字母表,有时甚至有多个字母表或拥有成千上万个字符的东方文字系统,以及许多特殊符号和标点符号。同样在现实生活中,大多数排序规则有许多规则,不仅用于区分大小写,还用于区分重音(“重音”是附加到字符上的标记,如德语Ö
),以及多字符映射(例如在两个德语排序规则中,Ö
=OE
的规则)。
MySQL 可以为您执行以下操作:
-
使用各种字符集存储字符串。
-
使用各种排序规则比较字符串。
-
在同一服务器、同一数据库甚至同一表中混合不同字符集或排序规则的字符串。
-
允许在任何级别指定字符集和排序规则。
要有效地使用这些功能,您必须了解可用的字符集和排序规则,如何更改默认设置以及它们如何影响字符串运算符和函数的行为。
12.2 MySQL 中的字符集和排序规则
12.2.1 字符集范围
12.2.2 元数据的 UTF-8
MySQL 服务器支持多种字符集,包括几种 Unicode 字符集。要显示可用的字符集,请使用INFORMATION_SCHEMA
CHARACTER_SETS
表或SHOW CHARACTER SET
语句。以下是部分列表。有关更完整的信息,请参见第 12.10 节,“支持的字符集和排序规则”。
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| binary | Binary pseudo charset | binary | 1 |
...
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
...
| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |
...
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
...
默认情况下,SHOW CHARACTER SET
语句显示所有可用的字符集。它接受一个可选的LIKE
或WHERE
子句,指示要匹配哪些字符集名称。以下示例显示了一些 Unicode 字符集(基于 Unicode 转换格式)。
mysql> SHOW CHARACTER SET LIKE 'utf%';
+---------+------------------+--------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+------------------+--------------------+--------+
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
+---------+------------------+--------------------+--------+
给定字符集始终至少有一个排序规则,大多数字符集有多个。要列出字符集的显示排序规则,请使用INFORMATION_SCHEMA
COLLATIONS
表或SHOW COLLATION
语句。
默认情况下,SHOW COLLATION
语句显示所有可用的排序规则。它接受一个可选的LIKE
或WHERE
子句,指示要显示哪些排序规则名称。例如,要查看默认字符集utf8mb4
的排序规则,请使用以下语句:
mysql> SHOW COLLATION WHERE Charset = 'utf8mb4';
+----------------------------+---------+-----+---------+----------+---------+---------------+
| Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+---------+-----+---------+----------+---------+---------------+
| utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD |
| utf8mb4_0900_as_ci | utf8mb4 | 305 | | Yes | 0 | NO PAD |
| utf8mb4_0900_as_cs | utf8mb4 | 278 | | Yes | 0 | NO PAD |
| utf8mb4_0900_bin | utf8mb4 | 309 | | Yes | 1 | NO PAD |
| utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 | PAD SPACE |
| utf8mb4_croatian_ci | utf8mb4 | 245 | | Yes | 8 | PAD SPACE |
| utf8mb4_cs_0900_ai_ci | utf8mb4 | 266 | | Yes | 0 | NO PAD |
| utf8mb4_cs_0900_as_cs | utf8mb4 | 289 | | Yes | 0 | NO PAD |
| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 | PAD SPACE |
| utf8mb4_danish_ci | utf8mb4 | 235 | | Yes | 8 | PAD SPACE |
| utf8mb4_da_0900_ai_ci | utf8mb4 | 267 | | Yes | 0 | NO PAD |
| utf8mb4_da_0900_as_cs | utf8mb4 | 290 | | Yes | 0 | NO PAD |
| utf8mb4_de_pb_0900_ai_ci | utf8mb4 | 256 | | Yes | 0 | NO PAD |
| utf8mb4_de_pb_0900_as_cs | utf8mb4 | 279 | | Yes | 0 | NO PAD |
| utf8mb4_eo_0900_ai_ci | utf8mb4 | 273 | | Yes | 0 | NO PAD |
| utf8mb4_eo_0900_as_cs | utf8mb4 | 296 | | Yes | 0 | NO PAD |
| utf8mb4_esperanto_ci | utf8mb4 | 241 | | Yes | 8 | PAD SPACE |
| utf8mb4_estonian_ci | utf8mb4 | 230 | | Yes | 8 | PAD SPACE |
| utf8mb4_es_0900_ai_ci | utf8mb4 | 263 | | Yes | 0 | NO PAD |
| utf8mb4_es_0900_as_cs | utf8mb4 | 286 | | Yes | 0 | NO PAD |
| utf8mb4_es_trad_0900_ai_ci | utf8mb4 | 270 | | Yes | 0 | NO PAD |
| utf8mb4_es_trad_0900_as_cs | utf8mb4 | 293 | | Yes | 0 | NO PAD |
| utf8mb4_et_0900_ai_ci | utf8mb4 | 262 | | Yes | 0 | NO PAD |
| utf8mb4_et_0900_as_cs | utf8mb4 | 285 | | Yes | 0 | NO PAD |
| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | PAD SPACE |
| utf8mb4_german2_ci | utf8mb4 | 244 | | Yes | 8 | PAD SPACE |
| utf8mb4_hr_0900_ai_ci | utf8mb4 | 275 | | Yes | 0 | NO PAD |
| utf8mb4_hr_0900_as_cs | utf8mb4 | 298 | | Yes | 0 | NO PAD |
| utf8mb4_hungarian_ci | utf8mb4 | 242 | | Yes | 8 | PAD SPACE |
| utf8mb4_hu_0900_ai_ci | utf8mb4 | 274 | | Yes | 0 | NO PAD |
| utf8mb4_hu_0900_as_cs | utf8mb4 | 297 | | Yes | 0 | NO PAD |
| utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8 | PAD SPACE |
| utf8mb4_is_0900_ai_ci | utf8mb4 | 257 | | Yes | 0 | NO PAD |
| utf8mb4_is_0900_as_cs | utf8mb4 | 280 | | Yes | 0 | NO PAD |
| utf8mb4_ja_0900_as_cs | utf8mb4 | 303 | | Yes | 0 | NO PAD |
| utf8mb4_ja_0900_as_cs_ks | utf8mb4 | 304 | | Yes | 24 | NO PAD |
| utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8 | PAD SPACE |
| utf8mb4_la_0900_ai_ci | utf8mb4 | 271 | | Yes | 0 | NO PAD |
| utf8mb4_la_0900_as_cs | utf8mb4 | 294 | | Yes | 0 | NO PAD |
| utf8mb4_lithuanian_ci | utf8mb4 | 236 | | Yes | 8 | PAD SPACE |
| utf8mb4_lt_0900_ai_ci | utf8mb4 | 268 | | Yes | 0 | NO PAD |
| utf8mb4_lt_0900_as_cs | utf8mb4 | 291 | | Yes | 0 | NO PAD |
| utf8mb4_lv_0900_ai_ci | utf8mb4 | 258 | | Yes | 0 | NO PAD |
| utf8mb4_lv_0900_as_cs | utf8mb4 | 281 | | Yes | 0 | NO PAD |
| utf8mb4_persian_ci | utf8mb4 | 240 | | Yes | 8 | PAD SPACE |
| utf8mb4_pl_0900_ai_ci | utf8mb4 | 261 | | Yes | 0 | NO PAD |
| utf8mb4_pl_0900_as_cs | utf8mb4 | 284 | | Yes | 0 | NO PAD |
| utf8mb4_polish_ci | utf8mb4 | 229 | | Yes | 8 | PAD SPACE |
| utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8 | PAD SPACE |
| utf8mb4_roman_ci | utf8mb4 | 239 | | Yes | 8 | PAD SPACE |
| utf8mb4_ro_0900_ai_ci | utf8mb4 | 259 | | Yes | 0 | NO PAD |
| utf8mb4_ro_0900_as_cs | utf8mb4 | 282 | | Yes | 0 | NO PAD |
| utf8mb4_ru_0900_ai_ci | utf8mb4 | 306 | | Yes | 0 | NO PAD |
| utf8mb4_ru_0900_as_cs | utf8mb4 | 307 | | Yes | 0 | NO PAD |
| utf8mb4_sinhala_ci | utf8mb4 | 243 | | Yes | 8 | PAD SPACE |
| utf8mb4_sk_0900_ai_ci | utf8mb4 | 269 | | Yes | 0 | NO PAD |
| utf8mb4_sk_0900_as_cs | utf8mb4 | 292 | | Yes | 0 | NO PAD |
| utf8mb4_slovak_ci | utf8mb4 | 237 | | Yes | 8 | PAD SPACE |
| utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8 | PAD SPACE |
| utf8mb4_sl_0900_ai_ci | utf8mb4 | 260 | | Yes | 0 | NO PAD |
| utf8mb4_sl_0900_as_cs | utf8mb4 | 283 | | Yes | 0 | NO PAD |
| utf8mb4_spanish2_ci | utf8mb4 | 238 | | Yes | 8 | PAD SPACE |
| utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8 | PAD SPACE |
| utf8mb4_sv_0900_ai_ci | utf8mb4 | 264 | | Yes | 0 | NO PAD |
| utf8mb4_sv_0900_as_cs | utf8mb4 | 287 | | Yes | 0 | NO PAD |
| utf8mb4_swedish_ci | utf8mb4 | 232 | | Yes | 8 | PAD SPACE |
| utf8mb4_tr_0900_ai_ci | utf8mb4 | 265 | | Yes | 0 | NO PAD |
| utf8mb4_tr_0900_as_cs | utf8mb4 | 288 | | Yes | 0 | NO PAD |
| utf8mb4_turkish_ci | utf8mb4 | 233 | | Yes | 8 | PAD SPACE |
| utf8mb4_unicode_520_ci | utf8mb4 | 246 | | Yes | 8 | PAD SPACE |
| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8 | PAD SPACE |
| utf8mb4_vietnamese_ci | utf8mb4 | 247 | | Yes | 8 | PAD SPACE |
| utf8mb4_vi_0900_ai_ci | utf8mb4 | 277 | | Yes | 0 | NO PAD |
| utf8mb4_vi_0900_as_cs | utf8mb4 | 300 | | Yes | 0 | NO PAD |
| utf8mb4_zh_0900_as_cs | utf8mb4 | 308 | | Yes | 0 | NO PAD |
+----------------------------+---------+-----+---------+----------+---------+---------------+
有关这些排序规则的更多信息,请参见第 12.10.1 节,“Unicode 字符集”。
排序规则具有以下一般特征:
-
两个不同的字符集不能具有相同的排序规则。
-
每个字符集都有一个默认排序。例如,
utf8mb4
和latin1
的默认排序分别为utf8mb4_0900_ai_ci
和latin1_swedish_ci
。INFORMATION_SCHEMA
CHARACTER_SETS
表和SHOW CHARACTER SET
语句指示每个字符集的默认排序。INFORMATION_SCHEMA
COLLATIONS
表和SHOW COLLATION
语句有一列指示每个排序是否是其字符集的默认排序(如果是,则为Yes
,否则为空)。 -
排序名称以它们关联的字符集的名称开头,通常后面跟着一个或多个后缀,表示其他排序特性。有关命名约定的更多信息,请参见第 12.3.1 节,“排序命名约定”。
当一个字符集有多个排序时,可能不清楚哪个排序对于特定应用程序最合适。为了避免选择不合适的排序,对具有代表性数据值的一些比较,以确保给定的排序按照您的预期对值进行排序。
12.2.1 字符集 repertoire
字符集的 repertoire 是集合中的字符。
字符串表达式具有 repertoire 属性,可以有两个值:
-
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
repertoire 的字符串可以安全地转换为具有UNICODE
repertoire 的任何字符串的字符集,而不会丢失信息。它也可以安全地转换为任何ascii
字符集的超集。(所有 MySQL 字符集都是ascii
的超集,除了swe7
,它重新使用一些标点字符作为瑞典重音字符。)
使用 repertoire 使得在许多情况下可以进行字符集转换,否则 MySQL 在协定强制性规则无法解决歧义时会返回“collations 混合不合法”错误。(有关强制性的信息,请参见 Section 12.8.4, “Collation Coercibility in Expressions”.)
以下讨论提供了表达式及其 repertoire 的示例,并描述了 repertoire 的使用如何改变字符串表达式的评估:
-
字符串常量的 repertoire 取决于字符串内容,可能与字符串字符集的 repertoire 不同。考虑以下语句:
SET NAMES utf8mb4; SELECT 'abc'; SELECT _utf8mb4'def';
尽管在前述每种情况中字符集为
utf8mb4
,但实际上字符串并不包含任何 ASCII 范围之外的字符,因此它们的 repertoire 是ASCII
而不是UNICODE
。 -
具有
ascii
字符集的列具有ASCII
repertoire,因为其字符集。在下表中,c1
具有ASCII
repertoire:CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET ascii);
以下示例说明了 repertoire 如何使得在没有 repertoire 的情况下发生错误时能够确定结果:
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;
没有 repertoire,会出现以下错误:
ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (ascii_general_ci,IMPLICIT) for operation 'concat'
使用 repertoire,可以发生从子集到超集(
ascii
到latin1
)的转换,并返回结果:+---------------+ | CONCAT(c1,c2) | +---------------+ | ab | +---------------+
-
具有一个字符串参数的函数继承其参数的 repertoire。
UPPER(_utf8mb4'abc')
的结果具有ASCII
repertoire,因为其参数具有ASCII
repertoire。(尽管有_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
字符集。第一个参数对结果字符集没有影响,即使表达式使用字符串值。
12.2.2 UTF-8 for Metadata
元数据是“关于数据的数据”。任何描述数据库的东西——而不是数据库的内容——都是元数据。因此,列名、数据库名、用户名称、版本名称以及SHOW
的大部分字符串结果都是元数据。这也适用于INFORMATION_SCHEMA
中表的内容,因为这些表定义上包含有关数据库对象的信息。
元数据的表示必须满足这些要求:
-
所有元数据必须使用相同的字符集。否则,
SHOW
语句或INFORMATION_SCHEMA
中表的SELECT
语句将无法正常工作,因为这些操作的结果中同一列中的不同行将使用不同的字符集。 -
元数据必须包含所有语言中的所有字符。否则,用户将无法使用自己的语言命名列和表。
为了满足这两个要求,MySQL 将元数据存储在 Unicode 字符集中,即 UTF-8。如果您从不使用带重音或非拉丁字符,这不会造成任何干扰。但如果您使用了,您应该知道元数据是 UTF-8 的。
元数据要求意味着USER()
、CURRENT_USER()
、SESSION_USER()
、SYSTEM_USER()
、DATABASE()
和VERSION()
函数的返回值默认为 UTF-8 字符集。
服务器将character_set_system
系统变量设置为元数据字符集的名称:
mysql> SHOW VARIABLES LIKE 'character_set_system';
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| character_set_system | utf8mb3 |
+----------------------+---------+
使用 Unicode 存储元数据不意味着服务器默认以character_set_system
字符集返回列标题和DESCRIBE
函数的结果。当您使用SELECT column1 FROM t
时,服务器将column1
名称本身以由character_set_results
系统变量的值确定的字符集返回给客户端,该系统变量的默认值为utf8mb4
。如果您希望服务器以不同的字符集传递元数据结果,请使用SET NAMES
语句强制服务器执行字符集转换。SET NAMES
设置character_set_results
和其他相关系统变量。(请参阅第 12.4 节,“连接字符集和校对规则”。)或者,客户端程序可以在从服务器接收结果后执行转换。客户端执行转换更有效,但并非所有客户端都能使用此选项。
如果character_set_results
设置为NULL
,则不执行任何转换,服务器将使用其原始字符集返回元数据(由character_set_system
指示的字符集)。
从服务器返回给客户端的错误消息会自动转换为客户端字符集,与元数据一样。
如果您在单个语句中使用(例如)USER()
函数进行比较或赋值,不用担心。MySQL 会为您执行一些自动转换。
SELECT * FROM t1 WHERE USER() = latin1_column;
这是因为在比较之前,latin1_column
的内容会自动转换为 UTF-8。
INSERT INTO t1 (latin1_column) SELECT USER();
这是因为在赋值之前,USER()
的内容会自动转换为latin1
。
尽管自动转换不符合 SQL 标准,但标准确实指出每个字符集(在支持的字符方面)都是 Unicode 的“子集”。因为“适用于超集的内容也适用于子集”是一个众所周知的原则,我们认为 Unicode 的排序规则可以用于与非 Unicode 字符串的比较。有关字符串强制转换的更多信息,请参阅第 12.8.4 节,“表达式中的排序规则可强制性”。
12.3 指定字符集和排序规则
12.3.1 排序命名约定
12.3.2 服务器字符集和排序规则
12.3.3 数据库字符集和排序规则
12.3.4 表字符集和排序规则
12.3.5 列字符集和排序规则
12.3.6 字符串文字字符集和排序规则
12.3.7 国家字符集
12.3.8 字符集引导符
12.3.9 字符集和排序规则分配示例
12.3.10 与其他 DBMS 的兼容性
在四个级别上有字符集和排序规则的默认设置:服务器、数据库、表和列。下面各节中的描述可能看起来复杂,但实践中发现,多级默认会导致自然和明显的结果。
CHARACTER SET
用于指定字符集的子句。CHARSET
可以作为 CHARACTER SET
的同义词使用。
字符集问题不仅影响数据存储,还影响客户端程序与 MySQL 服务器之间的通信。如果希望客户端程序使用与默认值不同的字符集与服务器通信,需要指定。例如,要使用 utf8mb4
Unicode 字符集,连接到服务器后发出以下语句:
SET NAMES 'utf8mb4';
欲了解有关客户端/服务器通信中与字符集相关的问题的更多信息,请参阅 第 12.4 节,“连接字符集和排序规则”。
12.3.1 排序命名约定
译文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-names.html
MySQL 排序名称遵循这些约定:
-
排序名称以其关联的字符集名称开头,通常后跟一个或多个指示其他排序特征的后缀。例如,
utf8mb4_0900_ai_ci
和latin1_swedish_ci
分别是utf8mb4
和latin1
字符集的排序。binary
字符集有一个单一的排序,也称为binary
,没有后缀。 -
语言特定的排序包括区域代码或语言名称。例如,
utf8mb4_tr_0900_ai_ci
和utf8mb4_hu_0900_ai_ci
分别使用土耳其和匈牙利的规则对utf8mb4
字符集进行排序。utf8mb4_turkish_ci
和utf8mb4_hungarian_ci
类似,但基于较早版本的 Unicode Collation Algorithm。 -
排序后缀指示排序是否区分大小写、重音或假名(或它们的某种组合),或者是二进制的。以下表格显示用于指示这些特征的后缀。
Table 12.1 排序后缀含义
后缀 含义 _ai
重音不敏感 _as
重音敏感 _ci
大小写不敏感 _cs
大小写敏感 _ks
假名敏感 _bin
二进制 对于未指定重音敏感性的非二进制排序名称,它由大小写敏感性确定。如果排序名称不包含
_ai
或_as
,名称中的_ci
暗示_ai
,名称中的_cs
暗示_as
。例如,latin1_general_ci
明确是大小写不敏感的,隐含是重音不敏感的,latin1_general_cs
明确是大小写敏感的,隐含是重音敏感的,utf8mb4_0900_ai_ci
明确是大小写不敏感和重音不敏感的。对于日语排序,
_ks
后缀表示排序是假名敏感的;也就是说,它区分片假名字符和平假名字符。没有_ks
后缀的日语排序不是假名敏感的,对片假名和平假名字符进行排序时视为相等。对于
binary
字符集的binary
排序,比较基于数字字节值。对于非二进制字符集的_bin
排序,比较基于数字字符编码值,对于多字节字符,这些值与字节值不同。有关binary
字符集的binary
排序和非二进制字符集的_bin
排序之间的差异,请参阅 Section 12.8.5, “The binary Collation Compared to _bin Collations”。 -
Unicode 字符集的排序名称可能包含版本号,以指示排序所基于的 Unicode 排序算法(UCA)的版本。在名称中没有版本号的基于 UCA 的排序使用版本 4.0.0 的 UCA 权重键。例如:
-
utf8mb4_0900_ai_ci
基于 UCA 9.0.0 权重键(www.unicode.org/Public/UCA/9.0.0/allkeys.txt
)。 -
utf8mb4_unicode_520_ci
基于 UCA 5.2.0 权重键(www.unicode.org/Public/UCA/5.2.0/allkeys.txt
)。 -
utf8mb4_unicode_ci
(没有指定版本)基于 UCA 4.0.0 权重键(www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt
)。
-
-
对于 Unicode 字符集,
*
xxx*_general_mysql500_ci
排序保留了原始*
xxx*_general_ci
排序的 5.1.24 之前的顺序,并允许升级用于在 MySQL 5.1.24 之前创建的表(Bug #27877)。
12.3.2 服务器字符集和校对
MySQL 服务器有一个服务器字符集和一个服务器校对。默认情况下,它们分别为utf8mb4
和utf8mb4_0900_ai_ci
,但可以在服务器启动时通过命令行或选项文件显式设置,并在运行时更改。
最初,服务器字符集和校对取决于启动mysqld时使用的选项。您可以使用--character-set-server
设置字符集。此外,您还可以添加--collation-server
设置校对。如果您没有指定字符集,那就相当于说--character-set-server=utf8mb4
。如果您只指定了字符集(例如,utf8mb4
)但没有指定校对,那就相当于说--character-set-server=utf8mb4
--collation-server=utf8mb4_0900_ai_ci
,因为utf8mb4_0900_ai_ci
是utf8mb4
的默认校对。因此,以下三个命令都具有相同的效果:
mysqld
mysqld --character-set-server=utf8mb4
mysqld --character-set-server=utf8mb4 \
--collation-server=utf8mb4_0900_ai_ci
更改设置的一种方法是重新编译。在从源代码构建时更改默认服务器字符集和校对,可以使用CMake的DEFAULT_CHARSET
和DEFAULT_COLLATION
选项。例如:
cmake . -DDEFAULT_CHARSET=latin1
或:
cmake . -DDEFAULT_CHARSET=latin1 \
-DDEFAULT_COLLATION=latin1_german1_ci
mysqld和CMake都会验证字符集/校对组合是否有效。如果无效,每个程序都会显示错误消息并终止。
如果在CREATE DATABASE
语句中未指定数据库字符集和校对,服务器字符集和校对将用作默认值。它们没有其他用途。
可以通过character_set_server
和collation_server
系统变量的值来确定当前服务器字符集和校对。这些变量可以在运行时更改。
12.3.3 数据库字符集和排序规则
每个数据库都有一个数据库字符集和一个数据库排序规则。CREATE DATABASE
和ALTER DATABASE
语句具有用于指定数据库字符集和排序规则的可选子句:
CREATE DATABASE *db_name*
[[DEFAULT] CHARACTER SET *charset_name*]
[[DEFAULT] COLLATE *collation_name*]
ALTER DATABASE *db_name*
[[DEFAULT] CHARACTER SET *charset_name*]
[[DEFAULT] COLLATE *collation_name*]
关键字SCHEMA
可以代替DATABASE
。
CHARACTER SET
和COLLATE
子句使得在同一 MySQL 服务器上创建具有不同字符集和排序规则的数据库成为可能。
数据库选项存储在数据字典中,可以通过检查信息模式SCHEMATA
表来查看。
示例:
CREATE DATABASE *db_name* CHARACTER SET latin1 COLLATE latin1_swedish_ci;
MySQL 按以下方式选择数据库字符集和数据库排序规则:
-
如果同时指定了
CHARACTER SET *
charset_name*
和COLLATE *
collation_name*
,则使用字符集charset_name
和排序规则collation_name
。 -
如果指定了
CHARACTER SET *
charset_name*
而没有指定COLLATE
,则使用字符集charset_name
及其默认排序规则。要查看每个字符集的默认排序规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。 -
如果指定了
COLLATE *
collation_name*
而没有指定CHARACTER SET
,则使用与collation_name
关联的字符集和排序规则collation_name
。 -
否则(既未指定
CHARACTER SET
也未指定COLLATE
),则使用服务器字符集和服务器排序规则。
可以从character_set_database
和collation_database
系统变量的值确定默认数据库的字符集和排序规则。每当默认数据库更改时,服务器会设置这些变量的值。如果没有默认数据库,则这些变量的值与相应的服务器级系统变量character_set_server
和collation_server
相同。
要查看给定数据库的默认字符集和排序规则,请使用以下语句:
USE *db_name*;
SELECT @@character_set_database, @@collation_database;
或者,要显示值而不更改默认数据库:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '*db_name*';
数据库字符集和排序规则影响服务器操作的这些方面:
-
对于
CREATE TABLE
语句,如果未指定表的字符集和校对规则,则数据库字符集和校对规则将作为表定义的默认值。要覆盖此设置,请提供明确的CHARACTER SET
和COLLATE
表选项。 -
对于包含没有
CHARACTER SET
子句的LOAD DATA
语句,服务器将使用character_set_database
系统变量指示的字符集来解释文件中的信息。要覆盖此设置,请提供明确的CHARACTER SET
子句。 -
对于存储过程(procedures)和函数(functions),在创建过程中使用的数据库字符集和校对规则将作为字符数据参数的字符集和校对规则,如果声明中未包含
CHARACTER SET
或COLLATE
属性。要覆盖此设置,请明确提供CHARACTER SET
和COLLATE
。
12.3.4 表字符集和排序规则
每个表都有一个表字符集和一个表排序规则。CREATE TABLE
和ALTER TABLE
语句有可选子句,用于指定表字符集和排序规则:
CREATE TABLE *tbl_name* (*column_list*)
[[DEFAULT] CHARACTER SET *charset_name*]
[COLLATE *collation_name*]]
ALTER TABLE *tbl_name*
[[DEFAULT] CHARACTER SET *charset_name*]
[COLLATE *collation_name*]
示例:
CREATE TABLE t1 ( ... )
CHARACTER SET latin1 COLLATE latin1_danish_ci;
MySQL 选择表字符集和排序规则的方式如下:
-
如果同时指定了
CHARACTER SET *
charset_name*
和COLLATE *
collation_name*
,则使用字符集charset_name
和排序规则collation_name
。 -
如果指定了
CHARACTER SET *
charset_name*
,但没有指定COLLATE
,则使用字符集charset_name
及其默认排序规则。要查看每个字符集的默认排序规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。 -
如果指定了
COLLATE *
collation_name*
,但没有指定CHARACTER SET
,则使用与collation_name
相关联的字符集和排序规则collation_name
。 -
否则(未指定
CHARACTER SET
或COLLATE
),则使用数据库字符集和排序规则。
如果在单独的列定义中未指定列字符集和排序规则,则表字符集和排序规则将用作列定义的默认值。表字符集和排序规则是 MySQL 的扩展;标准 SQL 中没有这样的东西。
12.3.5 列字符集和排序规则
每个“字符”列(即CHAR
、VARCHAR
类型的列,TEXT
类型,或任何同义词)都有一个列字符集和一个列排序规则。用于CREATE TABLE
和ALTER TABLE
的列定义语法具有可选子句,用于指定列字符集和排序规则:
*col_name* {CHAR | VARCHAR | TEXT} (*col_length*)
[CHARACTER SET *charset_name*]
[COLLATE *collation_name*]
这些子句也可用于ENUM
和SET
列:
*col_name* {ENUM | SET} (*val_list*)
[CHARACTER SET *charset_name*]
[COLLATE *collation_name*]
例如:
CREATE TABLE t1
(
col1 VARCHAR(5)
CHARACTER SET latin1
COLLATE latin1_german1_ci
);
ALTER TABLE t1 MODIFY
col1 VARCHAR(5)
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
MySQL 选择列的字符集和排序规则的方式如下:
-
如果同时指定了
CHARACTER SET *
charset_name*
和COLLATE *
collation_name*
,则使用字符集charset_name
和排序规则collation_name
。CREATE TABLE t1 ( col1 CHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ) CHARACTER SET latin1 COLLATE latin1_bin;
该列已指定字符集和排序规则,因此使用它们。该列的字符集为
utf8mb4
,排序规则为utf8mb4_unicode_ci
。 -
如果指定了
CHARACTER SET *
charset_name*
但未指定COLLATE
,则使用字符集charset_name
及其默认排序规则。CREATE TABLE t1 ( col1 CHAR(10) CHARACTER SET utf8mb4 ) CHARACTER SET latin1 COLLATE latin1_bin;
对于该列,指定了字符集,但未指定排序规则。该列的字符集为
utf8mb4
,默认排序规则为utf8mb4_0900_ai_ci
。要查看每个字符集的默认排序规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。 -
如果指定了
COLLATE *
collation_name*
但未指定CHARACTER SET
,则使用与collation_name
相关联的字符集和排序规则collation_name
。CREATE TABLE t1 ( col1 CHAR(10) COLLATE utf8mb4_polish_ci ) CHARACTER SET latin1 COLLATE latin1_bin;
对于该列,指定了排序规则,但未指定字符集。该列的排序规则为
utf8mb4_polish_ci
,字符集为与排序规则相关联的字符集,即utf8mb4
。 -
否则(既未指定
CHARACTER SET
也未指定COLLATE
),则使用表的字符集和排序规则。CREATE TABLE t1 ( col1 CHAR(10) ) CHARACTER SET latin1 COLLATE latin1_bin;
对于该列,既未指定字符集也未指定排序规则,因此使用表的默认设置。该列的字符集为
latin1
,排序规则为latin1_bin
。
CHARACTER SET
和COLLATE
子句是标准 SQL。
如果使用ALTER TABLE
将列从一个字符集转换为另一个字符集,MySQL 会尝试映射数据值,但如果字符集不兼容,则可能会丢失数据。
12.3.6 字符字符串字面量的字符集和校对规则
每个字符字符串字面量都有一个字符集和一个校对规则。
对于简单语句SELECT '*
string*'
,该字符串具有由character_set_connection
和collation_connection
系统变量定义的连接默认字符集和���对规则。
字符字符串字面量可以具有可选的字符集引导符和COLLATE
子句,以指定其为使用特定字符集和校对规则的字符串:
[_*charset_name*]'*string*' [COLLATE *collation_name*]
_*
charset_name*
表达式在形式上称为引导符。它告诉解析器,“接下来的字符串使用字符集charset_name
。”引导符不会像CONVERT()
那样将字符串转换为引导符字符集。它不会改变字符串值,尽管可能会发生填充。引导符只是一个信号。参见第 12.3.8 节,“字符集引导符”。
例子:
SELECT 'abc';
SELECT _latin1'abc';
SELECT _binary'abc';
SELECT _utf8mb4'abc' COLLATE utf8mb4_danish_ci;
字符集引导符和COLLATE
子句按照标准 SQL 规范实现。
MySQL 确定字符字符串字面量的字符集和校对规则的方式如下:
-
如果同时指定了
_charset_name
和COLLATE *
collation_name*
,则使用字符集charset_name
和校对规则collation_name
。collation_name
必须是charset_name
的允许校对规则。 -
如果
_charset_name
被指定但未指定COLLATE
,则使用字符集charset_name
及其默认校对规则。要查看每个字符集的默认校对规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。 -
如果未指定
_charset_name
但指定了COLLATE *
collation_name*
,则使用由character_set_connection
系统变量给出的连接默认字符集和校对规则collation_name
。collation_name
必须是连接默认字符集的允许校对规则。 -
否则(既未指定
_charset_name
也未指定COLLATE *
collation_name*
),则使用由character_set_connection
和collation_connection
系统变量给出的连接默认字符集和校对规则。
例子:
-
一个使用
latin1
字符集和latin1_german1_ci
校对规则的非二进制字符串:SELECT _latin1'Müller' COLLATE latin1_german1_ci;
-
一个带有
utf8mb4
字符集和其默认排序规则(即utf8mb4_0900_ai_ci
)的非二进制字符串:SELECT _utf8mb4'Müller';
-
一个带有
binary
字符集和其默认排序规则(即binary
)的二进制字符串:SELECT _binary'Müller';
-
一个带有连接默认字符集和
utf8mb4_0900_ai_ci
排序规则的非二进制字符串(如果连接字符集不是utf8mb4
,则失败):SELECT 'Müller' COLLATE utf8mb4_0900_ai_ci;
-
一个带有连接默认字符集和排序规则的字符串:
SELECT 'Müller';
一个引导符指示了接下来字符串的字符集,但不会改变解析器在字符串内部执行转义处理的方式。转义始终由解析器根据character_set_connection
给定的字符集来解释。
以下示例显示,即使有引导符存在,转义处理仍然使用character_set_connection
。这些示例使用SET NAMES
(更改character_set_connection
的内容,如第 12.4 节“连接字符集和排序规则”中所讨论的),并使用HEX()
函数显示结果字符串,以便查看确切的字符串内容。
示例 1:
mysql> SET NAMES latin1;
mysql> SELECT HEX('à\n'), HEX(_sjis'à\n');
+------------+-----------------+
| HEX('à\n') | HEX(_sjis'à\n') |
+------------+-----------------+
| E00A | E00A |
+------------+-----------------+
这里,à
(十六进制值E0
)后面跟着\n
,这是换行的转义序列。转义序列使用latin1
的character_set_connection
值来产生一个字面换行(十六进制值0A
)。即使对于第二个字符串也是如此。也就是说,_sjis
引导符不会影响解析器的转义处理。
示例 2:
mysql> SET NAMES sjis;
mysql> SELECT HEX('à\n'), HEX(_latin1'à\n');
+------------+-------------------+
| HEX('à\n') | HEX(_latin1'à\n') |
+------------+-------------------+
| E05C6E | E05C6E |
+------------+-------------------+
这里,character_set_connection
是sjis
,一个字符集,其中à
后面跟着\
(十六进制值05
和5C
)是一个有效的多字节字符。因此,字符串的前两个字节被解释为一个单个的sjis
字符,\
不被解释为转义字符。接下来的n
(十六进制值6E
)不被解释为转义序列的一部分。即使对于第二个字符串也是如此;_latin1
引导符不会影响转义处理。
12.3.7 国家字符集
标准 SQL 将NCHAR
或NATIONAL CHAR
定义为指示CHAR
列应使用某个预定义字符集的方法。MySQL 使用utf8
作为这个预定义字符集。例如,以下数据类型声明是等效的:
CHAR(10) CHARACTER SET utf8
NATIONAL CHARACTER(10)
NCHAR(10)
此外还有这些:
VARCHAR(10) CHARACTER SET utf8
NATIONAL VARCHAR(10)
NVARCHAR(10)
NCHAR VARCHAR(10)
NATIONAL CHARACTER VARYING(10)
NATIONAL CHAR VARYING(10)
您可以使用N'*
literal*'
(或n'*
literal*'
)来创建一个国家字符集中的字符串。以下语句是等效的:
SELECT N'some text';
SELECT n'some text';
SELECT _utf8'some text';
MySQL 8.0 将国家字符集解释为utf8mb3
,这种方式现在已经被弃用。因此,使用NATIONAL CHARACTER
或其同义词之一来定义数据库、表或列的字符集会引发类似于以下警告:
NATIONAL/NCHAR/NVARCHAR implies the character set UTF8MB3, which will be
replaced by UTF8MB4 in a future release. Please consider using CHAR(x) CHARACTER
SET UTF8MB4 in order to be unambiguous.
12.3.8 字符集引导符
字符串文字、十六进制文字或位值文字可以有可选的字符集引导符和COLLATE
子句,以指定它为使用特定字符集和校对规则的字符串:
[_*charset_name*] *literal* [COLLATE *collation_name*]
_*
charset_name*
表达式在形式上称为引导符。它告诉解析器,“接下来的字符串使用字符集charset_name
。” 引导符不会像CONVERT()
那样将字符串更改为引导符字符集。它不会更改字符串值,尽管可能会发生填充。引导符只是一个信号。
对于字符串文字,引导符和字符串之间的空格是允许但是可选的。
对于字符集文字,引导符表示后续字符串的字符集,但不会改变解析器如何在字符串内执行转义处理。转义始终由解析器根据character_set_connection
给定的字符集进行解释。有关更多讨论和示例,请参见第 12.3.6 节,“字符串文字的字符集和校对规则”。
例子:
SELECT 'abc';
SELECT _latin1'abc';
SELECT _binary'abc';
SELECT _utf8mb4'abc' COLLATE utf8mb4_danish_ci;
SELECT _latin1 X'4D7953514C';
SELECT _utf8mb4 0x4D7953514C COLLATE utf8mb4_danish_ci;
SELECT _latin1 b'1000001';
SELECT _utf8mb4 0b1000001 COLLATE utf8mb4_danish_ci;
字符集引导符和COLLATE
子句按照标准 SQL 规范实现。
字符串文字可以通过使用_binary
引导符指定为二进制字符串。十六进制文字和位值文字默认为二进制字符串,因此允许使用_binary
,但通常是不必要的。在 MySQL 8.0 及更高版本中,位操作允许数字或二进制字符串参数,但默认情况下将十六进制和位文字视为数字。为了明确指定这些文字的二进制字符串上下文,对于这些文字至少一个参数使用_binary
引导符:
mysql> SET @v1 = X'000D' | X'0BC0';
mysql> SET @v2 = _binary X'000D' | X'0BC0';
mysql> SELECT HEX(@v1), HEX(@v2);
+----------+----------+
| HEX(@v1) | HEX(@v2) |
+----------+----------+
| BCD | 0BCD |
+----------+----------+
对于位操作,显示的结果看起来相似,但没有_binary
的结果是一个BIGINT
值,而有_binary
的结果是一个二进制字符串。由于结果类型的差异,显示的值也不同:高位 0 数字不会显示在数值结果中。
MySQL 确定字符串文字、十六进制文字或位值文字的字符集和校对规则的方式如下:
-
如果同时指定了
_charset_name
和COLLATE *
collation_name*
,则使用字符集charset_name
和校对规则collation_name
。collation_name
必须是charset_name
的允许校对规则。 -
如果指定了
_charset_name
但未指定COLLATE
,则使用字符集charset_name
及其默认排序规则。要查看每个字符集的默认排序规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。 -
如果未指定
_charset_name
但指定了COLLATE *
collation_name*
:-
对于字符字符串字面值,使用由
character_set_connection
系统变量给出的连接默认字符集和排序规则collation_name
。collation_name
必须是连接默认字符集的允许排序规则。 -
对于十六进制字面值或位值字面值,唯一允许的排序规则是
binary
,因为这些类型的字面值默认为二进制字符串。
-
-
否则(既未指定
_charset_name
也未指定COLLATE *
collation_name*
):-
对于字符字符串字面值,使用由
character_set_connection
和collation_connection
系统变量给出的连接默认字符集和排序规则。 -
对于十六进制字面值或位值字面值,字符集和排序规则为
binary
。
-
例子:
-
具有
latin1
字符集和latin1_german1_ci
排序规则的非二进制字符串:SELECT _latin1'Müller' COLLATE latin1_german1_ci; SELECT _latin1 X'0A0D' COLLATE latin1_german1_ci; SELECT _latin1 b'0110' COLLATE latin1_german1_ci;
-
具有
utf8mb4
字符集及其默认排序规则(即utf8mb4_0900_ai_ci
)的非二进制字符串:SELECT _utf8mb4'Müller'; SELECT _utf8mb4 X'0A0D'; SELECT _utf8mb4 b'0110';
-
具有
binary
字符集及其默认排序规则(即binary
)的二进制字符串:SELECT _binary'Müller'; SELECT X'0A0D'; SELECT b'0110';
十六进制字面值和位值字面值不需要引导符,因为它们默认为二进制字符串。
-
一个具有连接默认字符集和
utf8mb4_0900_ai_ci
排序规则的非二进制字符串(如果连接字符集不是utf8mb4
,则失败):SELECT 'Müller' COLLATE utf8mb4_0900_ai_ci;
这个构造(
COLLATE
only)对十六进制字面值或位字面值不起作用,因为它们的字符集是binary
,无论连接字符集如何,而binary
与utf8mb4_0900_ai_ci
排序规则不兼容。在没有引导符的情况下,唯一允许的COLLATE
子句是COLLATE binary
。 -
一个具有连接默认字符集和排序规则的字符串:
SELECT 'Müller';
12.3.9 字符集和排序规则分配示例
以下示例展示了 MySQL 如何确定默认字符集和排序规则值。
示例 1:表和列定义
CREATE TABLE t1
(
c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci
) DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;
这里有一个具有latin1
字符集和latin1_german1_ci
排序规则的列。定义是明确的,因此很直接。请注意,在latin2
表中存储latin1
列没有问题。
示例 2:表和列定义
CREATE TABLE t1
(
c1 CHAR(10) CHARACTER SET latin1
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
这次我们有一个具有latin1
字符集和默认排序规则的列。虽然看起来很自然,但默认排序规则并不是从表级别获取的。相反,因为latin1
的默认排序规则始终是latin1_swedish_ci
,列c1
的排序规则是latin1_swedish_ci
(而不是latin1_danish_ci
)。
示例 3:表和列定义
CREATE TABLE t1
(
c1 CHAR(10)
) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;
我们有一个具有默认字符集和默认排序规则的列。在这种情况下,MySQL 会检查表级别以确定列字符集和排序规则。因此,列c1
的字符集是latin1
,排序规则是latin1_danish_ci
。
示例 4:数据库、表和列定义
CREATE DATABASE d1
DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_cs;
USE d1;
CREATE TABLE t1
(
c1 CHAR(10)
);
创建一个没有指定字符集和排序规则的列。我们也没有在表级别指定字符集和排序规则。在这种情况下,MySQL 会检查数据库级别以确定表设置,然后成为列设置。因此,列c1
的字符集是latin2
,排序规则是latin2_czech_cs
。
12.3.10 与其他 DBMS 的兼容性
对于 MaxDB 兼容性,这两个语句是相同的:
CREATE TABLE t1 (f1 CHAR(*N*) UNICODE);
CREATE TABLE t1 (f1 CHAR(*N*) CHARACTER SET ucs2);
UNICODE
属性和ucs2
字符集在 MySQL 8.0.28 中已被弃用。
12.4 连接字符集和排序规则
“连接”是客户端程序连接到服务器时建立的会话,通过该会话与服务器进行交互。客户端通过会话连接发送 SQL 语句,如查询。服务器通过连接向客户端发送响应,如结果集或错误消息。
-
连接字符集和排序规则系统变量
-
不允许的客户端字符集
-
客户端程序连接字符集配置
-
连接字符集配置的 SQL 语句
-
连接字符集错误处理
连接字符集和排序规则系统变量
几个字符集和排序规则系统变量与客户端与服务器的交互相关。其中一些在前面的章节中已经提到:
-
character_set_server
和collation_server
系统变量指示服务器的字符集和排序规则。参见 第 12.3.2 节,“服务器字符集和排序规则”。 -
character_set_database
和collation_database
系统变量指示默认数据库的字符集和排序规则。参见 第 12.3.3 节,“数据库字符集和排序规则”。
处理客户端与服务器之间连接流量涉及到其他字符集和排序规则系统变量。每个客户端都有特定于会话的连接相关字符集和排序规则系统变量。这些会话系统变量值在连接时初始化,但可以在会话中更改。
关于客户端连接的字符集和排序规则处理的几个问题可以通过系统变量来回答:
-
当语句离开客户端时,它们处于什么字符集?
服务器将
character_set_client
系统变量视为客户端发送的语句的字符集。注意
一些字符集不能用作客户端字符集。请参阅不允许的客户端字符集。
-
服务器在接收语句后应将其转换为哪种字符集?
为了确定这一点,服务器使用
character_set_connection
和collation_connection
系统变量:-
服务器将客户端发送的语句从
character_set_client
转换为character_set_connection
。例外:对于具有诸如_utf8mb4
或_latin2
之类的引导符的字符串文字,引导符确定字符集。请参阅第 12.3.8 节,“字符集引导符”。 -
collation_connection
对于文字字符串的比较很重要。对于与列值进行比较的字符串,collation_connection
并不重要,因为列有自己的排序规则,其具有更高的排序规则优先级(参见第 12.8.4 节,“表达式中的排序规则可强制性”)。
-
-
服务器在将查询结果返回给客户端之前应将其转换为哪种字符集?
character_set_results
系统变量指示服务器将查询结果返回给客户端的字符集。这包括结果数据,如列值,结果元数据,如列名,以及错误消息。要告诉服务器不要对结果集或错误消息进行任何转换,请将
character_set_results
设置为NULL
或binary
:SET character_set_results = NULL; SET character_set_results = binary;
有关字符集和错误消息的更多信息,请参阅第 12.6 节,“错误消息字符集”。
要查看适用于当前会话的字符集和排序规则系统变量的值,请使用此语句:
SELECT * FROM performance_schema.session_variables
WHERE VARIABLE_NAME IN (
'character_set_client', 'character_set_connection',
'character_set_results', 'collation_connection'
) ORDER BY VARIABLE_NAME;
以下更简单的语句也显示连接变量,但同时包括其他相关变量。它们可以用于查看所有字符集和排序规则系统变量:
SHOW SESSION VARIABLES LIKE 'character\_set\_%';
SHOW SESSION VARIABLES LIKE 'collation\_%';
客户端可以微调这些变量的设置,或依赖默认值(在这种情况下,您可以跳过本节的其余部分)。 如果不使用默认值,则必须为每个连接到服务器的连接更改字符设置。
不允许的客户端字符集
character_set_client
系统变量不能设置为某些字符集:
ucs2
utf16
utf16le
utf32
尝试将任何这些字符集用作客户端字符集会产生错误:
mysql> SET character_set_client = 'ucs2';
ERROR 1231 (42000): Variable 'character_set_client'
can't be set to the value of 'ucs2'
如果在以下情况下使用任何这些字符集,都会发生相同的错误,所有这些情况都会尝试将character_set_client
设置为指定的字符集:
-
MySQL 客户端程序(如mysql和mysqladmin)使用的
--default-character-set=*
charset_name*
命令选项。 -
SET NAMES '*
charset_name*'
语句。 -
SET CHARACTER SET '*
charset_name*'
语句。
客户端程序连接字符集配置
当客户端连接到服务器时,它指示要用于与服务器通信的字符集。 (实际上,客户端指示该字符集的默认排序规则,从中服务器可以确定字符集。)服务器使用此信息将character_set_client
、character_set_results
、character_set_connection
系统变量设置为字符集,并将collation_connection
设置为字符集的默认排序规则。 实际上,服务器执行了一个等效的SET NAMES
操作。
如果服务器不支持请求的字符集或排序规则,它将回退到使用服务器字符集和排序规则来配置连接。有关此回退行为的更多详细信息,请参阅连接字符集错误处理。
mysql, mysqladmin, mysqlcheck, mysqlimport, 和 mysqlshow 客户端程序确定要使用的默认字符集如下:
-
在没有其他信息的情况下,每个客户端使用编译时的默认字符集,通常为
utf8mb4
。 -
每个客户端可以根据操作系统设置自动检测要使用的字符集,例如在 Unix 系统上的
LANG
或LC_ALL
区域设置环境变量的值,或 Windows 系统上的代码页设置。对于从操作系统获取区域设置的系统,客户端使用它来设置默认字符集,而不是使用编译时的默认值。例如,将LANG
设置为ru_RU.KOI8-R
会导致使用koi8r
字符集。因此,用户可以配置其环境中的区域设置供 MySQL 客户端使用。如果没有完全匹配,操作系统字符集将映射到最接近的 MySQL 字符集。如果客户端不支持匹配的字符集,则使用编译时的默认值。例如,
utf8
和utf-8
映射到utf8mb4
,而ucs2
不支持作为连接字符集,因此映射到编译时的默认值。C 应用程序可以根据操作系统设置使用字符集自动检测,方法是在连接到服务器之前调用
mysql_options()
如下:mysql_options(mysql, MYSQL_SET_CHARSET_NAME, MYSQL_AUTODETECT_CHARSET_NAME);
-
每个客户端支持
--default-character-set
选项,允许用户显式指定字符集以覆盖客户端否则确定的默认值。注意
有些字符集不能用作客户端字符集。尝试使用它们与
--default-character-set
会产生错误。参见不允许的客户端字符集。
使用mysql客户端,如果要使用与默认字符集不同的字符集,您可以在每次连接到服务器时显式执行一个SET NAMES
语句(参见客户端程序连接字符集配置)。为了更轻松地实现相同的结果,可以在选项文件中指定字符集。例如,以下选项文件设置在每次调用mysql时将三个与连接相关的字符集系统变量设置为koi8r
:
[mysql]
default-character-set=koi8r
如果您正在使用启用了自动重新连接的mysql客户端(不建议),最好使用charset
命令而不是SET NAMES
。例如:
mysql> charset koi8r
Charset changed
charset
命令发出一个SET NAMES
语句,并在连接断开后重新连接时更改mysql使用的默认字符集。
在配置客户端程序时,还必须考虑它们执行的环境。参见第 12.5 节,“配置应用程序字符集和排序规则”。
用于连接字符集配置的 SQL 语句
建立连接后,客户端可以为当前会话更改字符集和排序规则系统变量。这些变量可以使用SET
语句单独更改,但另外两个更方便的语句会作为一组影响与连接相关的字符集系统变量:
-
SET NAMES '*
charset_name*' [COLLATE '*
collation_name*']
SET NAMES
指示客户端用于向服务器发送 SQL 语句的字符集。因此,SET NAMES 'cp1251'
告诉服务器,“来自此客户端的未来传入消息使用字符集cp1251
。”它还指定服务器在将结果发送回客户端时应使用的字符集。(例如,如果使用产生结果集的SELECT
语句,则指定用于列值的字符集。)一个
SET NAMES '*
charset_name*'
语句等同于这三个语句:SET character_set_client = *charset_name*; SET character_set_results = *charset_name*; SET character_set_connection = *charset_name*;
将
character_set_connection
设置为charset_name
也会隐式地将collation_connection
设置为charset_name
的默认排序规则。不需要显式设置该排序规则。要指定用于collation_connection
的特定排序规则,请添加COLLATE
子句:SET NAMES '*charset_name*' COLLATE '*collation_name*'
-
SET CHARACTER SET '*
charset_name*'
SET CHARACTER SET
类似于SET NAMES
,但将character_set_connection
和collation_connection
设置为character_set_database
和collation_database
(如前所述,指示默认数据库的字符集和排序规则)。SET CHARACTER SET *
charset_name*
语句等同于这三个语句:SET character_set_client = *charset_name*; SET character_set_results = *charset_name*; SET collation_connection = @@collation_database;
设置
collation_connection
也会隐式地将character_set_connection
设置为与排序规则相关联的字符集(等同于执行SET character_set_connection = @@character_set_database
)。不需要显式设置character_set_connection
。
注意
有些字符集不能作为客户端字符集使用。尝试在SET NAMES
或SET CHARACTER SET
中使用它们会产生错误。请参阅不允许的客户端字符集。
例如:假设column1
定义为CHAR(5) CHARACTER SET latin2
。如果不在发出SELECT column1 FROM t
之前说SET NAMES
或SET CHARACTER SET
,那么服务器会使用客户端连接时指定的字符集发送column1
的所有值。另一方面,如果在发出SELECT
语句之前说SET NAMES 'latin1'
或SET CHARACTER SET 'latin1'
,服务器会在发送结果之前将latin2
值转换为latin1
。对于不在两个字符集中的字符,转换可能会有损失。
连接字符集错误处理
尝试使用不合适的连接字符集或排序规则可能会产生错误,或导致服务器回退到给定连接的默认字符集和排序规则。本节描述了在配置连接字符集时可能出现的问题。这些问题可能在建立连接时或在已建立连接中更改字符集时发生。
-
连接时错误处理
-
运行时错误处理
连接时错误处理
一些字符集不能用作客户端字符集;参见不允许的客户端字符集。如果指定了一个有效但不允许作为客户端字符集的字符集,服务器会返回一个错误:
$> mysql --default-character-set=ucs2
ERROR 1231 (42000): Variable 'character_set_client' can't be set to
the value of 'ucs2'
如果指定了客户端不认识的字符集,会产生错误:
$> mysql --default-character-set=bogus
mysql: Character set 'bogus' is not a compiled character set and is
not specified in the '/usr/local/mysql/share/charsets/Index.xml' file
ERROR 2019 (HY000): Can't initialize character set bogus
(path: /usr/local/mysql/share/charsets/)
如果指定了客户端识别但服务器不识别的字符集,服务器会回退到其默认字符集和排序规则。假设服务器配置为使用latin1
和latin1_swedish_ci
作为默认值,并且不认识gb18030
作为有效字符集。指定--default-character-set=gb18030
的客户端可以连接到服务器,但结果的字符集不是客户端想要的:
mysql> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
...
| character_set_results | latin1 |
...
+--------------------------+--------+
mysql> SHOW SESSION VARIABLES LIKE 'collation_connection';
+----------------------+-------------------+
| Variable_name | Value |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
+----------------------+-------------------+
您可以看到连接系统变量已设置为反映latin1
和latin1_swedish_ci
的字符集和排序规则。这是因为服务器无法满足客户端字符集请求并回退到其默认值。
在这种情况下,客户端无法使用它想要的字符集,因为服务器不支持。客户端必须要么愿意使用不同的字符集,要么连接到支持所需字符集的不同服务器。
在更微妙的情况下也会出现相同的问题:当客户端告诉服务器使用服务器识别的字符集,但客户端端默认排序规则在服务器端是未知的。例如,当一个 MySQL 8.0 客户端想要使用utf8mb4
作为客户端字符集连接到 MySQL 5.7 服务器时,就会出现这种情况。指定--default-character-set=utf8mb4
的客户端可以连接到服务器。然而,与前面的例子一样,服务器会回退到其默认字符集和排序规则,而不是客户端请求的内容:
mysql> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
...
| character_set_results | latin1 |
...
+--------------------------+--------+
mysql> SHOW SESSION VARIABLES LIKE 'collation_connection';
+----------------------+-------------------+
| Variable_name | Value |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
+----------------------+-------------------+
为什么会发生这种情况?毕竟,utf8mb4
是 8.0 客户端和 5.7 服务器都知道的,所以它们都识别它。要理解这种行为,有必要了解当客户端告诉服务器它想要使用哪种字符集时,实际上是告诉服务器该字符集的默认排序规则。因此,上述行为是由多种因素的组合造成的:
-
utf8mb4
的默认排序规则在 MySQL 5.7 和 8.0 之间不同(5.7 为utf8mb4_general_ci
,8.0 为utf8mb4_0900_ai_ci
)。 -
当 8.0 客户端请求一个字符集为
utf8mb4
时,发送给服务器的是默认的 8.0utf8mb4
排序规则;即utf8mb4_0900_ai_ci
。 -
utf8mb4_0900_ai_ci
仅在 MySQL 8.0 中实现,因此 5.7 服务器不识别它。 -
由于 5.7 服务器不识别
utf8mb4_0900_ai_ci
,无法满足客户端字符集请求,因此回退到其默认字符集和排序规则(latin1
和latin1_swedish_ci
)。
在这种情况下,客户端仍然可以在连接后发出 SET NAMES 'utf8mb4'
语句来使用 utf8mb4
。结果的排序规则是 5.7 默认的 utf8mb4
排序规则;即 utf8mb4_general_ci
。如果客户端还想要 utf8mb4_0900_ai_ci
的排序规则,由于服务器不识别该排序规则,无法实现。客户端必须要么愿意使用不同的 utf8mb4
排序规则,要么连接到 MySQL 8.0 或更高版本的服务器。
运行时错误处理
在已建立的连接中,客户端可以通过 SET NAMES
或 SET CHARACTER SET
请求更改连接字符集和排序规则。
一些字符集不能用作客户端字符集;请参阅不允许的客户端字符集。如果指定了一个有效但不允许作为客户端字符集的字符集,服务器会返回一个错误:
mysql> SET NAMES 'ucs2';
ERROR 1231 (42000): Variable 'character_set_client' can't be set to
the value of 'ucs2'
如果服务器不识别字符集(或排序规则),则会产生错误:
mysql> SET NAMES 'bogus';
ERROR 1115 (42000): Unknown character set: 'bogus'
mysql> SET NAMES 'utf8mb4' COLLATE 'bogus';
ERROR 1273 (HY000): Unknown collation: 'bogus'
提示
一个想要验证服务器是否接受其请求的字符集的客户端可以在连接后执行以下语句,并检查结果是否是预期的字符集:
SELECT @@character_set_client;
12.5 配置应用程序字符集和校对规则
原文:
dev.mysql.com/doc/refman/8.0/en/charset-applications.html
对于使用默认 MySQL 字符集和校对规则(utf8mb4
、utf8mb4_0900_ai_ci
)存储数据的应用程序,不需要特殊配置。如果应用程序需要使用不同的字符集或校对规则进行数据存储,可以通过多种方式配置字符集信息:
-
为每个数据库指定字符设置。例如,使用一个数据库的应用程序可能使用
utf8mb4
的默认设置,而使用另一个数据库的应用程序可能使用sjis
。 -
在服务器启动时指定字符设置。这将导致服务器对所有未做其他安排的应用程序使用给定设置。
-
如果从源代码构建 MySQL,请在配置时指定字符设置。这将导致服务器将给定设置用作所有应用程序的默认设置,而无需在服务器启动时指定它们。
当不同应用程序需要不同的字符设置时,每个数据库的技术提供了很大的灵活性。如果大多数或所有应用程序使用相同的字符集,则在服务器启动时或配置时指定字符设置可能是最方便的。
对于每个数据库或服务器启动技术,这些设置控制数据存储的字符集。应用程序还必须告诉服务器在客户端/服务器通信中使用哪种字符集,如下面的说明所述。
这里展示的示例假定在特定情境下使用latin1
字符集和latin1_swedish_ci
校对规则,作为utf8mb4
和utf8mb4_0900_ai_ci
默认设置的替代方案。
-
为每个数据库指定字符设置。 要创建一个数据库,使其表使用给定的默认字符集和校对规则进行数据存储,请使用类似于以下的
CREATE DATABASE
语句:CREATE DATABASE mydb CHARACTER SET latin1 COLLATE latin1_swedish_ci;
数据库中创建的表默认使用
latin1
和latin1_swedish_ci
作为任何字符列的字符集。使用数据库的应用程序在每次连接时也应配置与服务器的连接。这可以通过连接后执行
SET NAMES 'latin1'
语句来完成。该语句可用于任何连接方法(mysql客户端、PHP 脚本等)。在某些情况下,可能可以通过其他方式配置连接以使用所需的字符集。例如,要使用mysql连接,可以指定
--default-character-set=latin1
命令行选项,以实现与SET NAMES 'latin1'
相同的效果。有关配置客户端连接的更多信息,请参见第 12.4 节,“连接字符集和校对规则”。
注意
如果您使用
ALTER DATABASE
更改数据库默认字符集或校对规则,则必须删除并重新创建数据库中使用这些默认设置的现有存储过程,以便它们使用新的默认设置。(在存储过程中,如果未明确指定字符集或校对规则,则具有字符数据类型的变量将使用数据库默认设置。请参见第 15.1.17 节,“CREATE PROCEDURE 和 CREATE FUNCTION 语句”。) -
在服务器启动时指定字符设置。 要在服务器启动时选择字符集和校对规则,请使用
--character-set-server
和--collation-server
选项。例如,要在选项文件中指定这些选项,请包含以下行:[mysqld] character-set-server=latin1 collation-server=latin1_swedish_ci
这些设置适用于整个服务器,并作为任何应用程序创建的数据库以及在这些数据库中创建的表的默认设置。
应用程序仍然需要在连接后使用
SET NAMES
或等效方法配置其连接,如前所述。您可能会尝试使用--init_connect="SET NAMES 'latin1'"
选项启动服务器,以使SET NAMES
自动为每个连接的客户端执行。但是,这可能会产生不一致的结果,因为具有CONNECTION_ADMIN
权限(或已弃用的SUPER
权限)的用户不会执行init_connect
值。 -
在 MySQL 配置时间指定字符设置。 如果您从源代码配置和构建 MySQL,可以使用
DEFAULT_CHARSET
和DEFAULT_COLLATION
CMake选项来选择字符集和校对规则:cmake . -DDEFAULT_CHARSET=latin1 \ -DDEFAULT_COLLATION=latin1_swedish_ci
结果服务器使用
latin1
和latin1_swedish_ci
作为数据库和表以及客户端连接的默认设置。在服务器启动时不需要使用--character-set-server
和--collation-server
来指定这些默认设置。应用程序也无需在连接到服务器后使用SET NAMES
或等效方法配置其连接。
无论您如何为应用程序配置 MySQL 字符集,您还必须考虑这些应用程序执行的环境。例如,如果您打算使用从编辑器中创建的文件中的 UTF-8 文本发送语句,您应该将文件的编辑环境设置为 UTF-8,以便文件编码正确,并且操作系统正确处理它。如果您在终端窗口中使用mysql客户端,窗口必须配置为使用 UTF-8,否则字符可能无法正确显示。对于在 Web 环境中执行的脚本,脚本必须正确处理字符编码以便与 MySQL 服务器交互,并且必须生成正确指示编码的页面,以便浏览器知道如何显示页面内容。例如,您可以在<head>
元素中包含此<meta>
标签:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
12.6 错误消息字符集
本节描述了 MySQL 服务器如何使用字符集构造错误消息。有关错误消息的语言(而不是字符集)的信息,请参见第 12.12 节,“设置错误消息语言”。有关配置错误日志的一般信息,请参见第 7.4.2 节,“错误日志”。
-
错误消息构造的字符集
-
错误消息处置的字符集
错误消息构造的字符集
服务器构造错误消息如下:
-
消息模板使用 UTF-8(
utf8mb3
)。 -
消息模板中的参数将被替换为适用于特定错误发生的值:
-
诸如表或列名的标识符在内部使用 UTF-8,因此它们被直接复制。
-
字符(非二进制)字符串值从其字符集转换为 UTF-8。
-
二进制字符串值在范围
0x20
至0x7E
的字节中被直接复制,对于范围之外的字节则使用\x
十六进制编码。例如,如果尝试将0x41CF9F
插入到VARBINARY
唯一列中导致重复键错误,则生成的错误消息将使用 UTF-8,并对一些字节进行十六进制编码:Duplicate entry 'A\xCF\x9F' for key 1
-
错误消息处置的字符集
一旦构造完成,错误消息可以由服务器写入错误日志或发送给客户端:
-
如果服务器将错误消息写入错误日志,则会按照构造的 UTF-8 格式写入,而不会转换为其他字符集。
-
如果服务器将错误消息发送给客户端程序,则服务器将其从 UTF-8 转换为由
character_set_results
系统变量指定的字符集。如果character_set_results
的值为NULL
或binary
,则不会进行转换。如果变量值为utf8mb3
或utf8mb4
,也不会进行转换,因为这些字符集包含了消息构造中使用的所有 UTF-8 字符。如果字符无法表示为
character_set_results
中的字符集,则在转换过程中可能会发生一些编码。编码使用 Unicode 代码点值:-
基本多语言平面(BMP)范围内的字符(
0x0000
至0xFFFF
)使用\*
nnnn*
表示。 -
超出 BMP 范围(
0x10000
至0x10FFFF
)的字符使用\+*
nnnnnn*
表示。
客户端可以设置
character_set_results
来控制他们接收错误消息的字符集。该变量可以直接设置,也可以通过诸如SET NAMES
等方式间接设置。有关character_set_results
的更多信息,请参见第 12.4 节,“连接字符集和校对”。 -
12.7 列字符集转换
要将二进制或非二进制字符串列转换为使用特定字符集,请使用ALTER TABLE
。要成功转换,必须满足以下条件之一:
-
如果列具有二进制数据类型(
BINARY
,VARBINARY
,BLOB
),则它包含的所有值必须使用单个字符集进行编码(您正在将列转换为的字符集)。如果使用二进制列存储多个字符集的信息,MySQL 无法知道哪些值使用哪个字符集,并且无法正确转换数据。 -
如果列具有非二进制数据类型(
CHAR
,VARCHAR
,TEXT
),其内容应该以列字符集编码,而不是其他字符集。如果内容以不同的字符集编码,您可以先将列转换为使用二进制数据类型,然后再转换为具有所需字符集的非二进制列。
假设表t
有一个名为col1
的二进制列,定义为VARBINARY(50)
。假设列中的信息使用单个字符集进行编码,您可以将其转换为具有该字符集的非二进制列。例如,如果col1
包含代表greek
字符集中字符的二进制数据,则可以按如下方式进行转换:
ALTER TABLE t MODIFY col1 VARCHAR(50) CHARACTER SET greek;
如果您的原始列类型为BINARY(50)
,您可以将其转换为CHAR(50)
,但结果值将在末尾填充0x00
字节,这可能是不希望的。要删除这些字节,请使用TRIM()
函数:
UPDATE t SET col1 = TRIM(TRAILING 0x00 FROM col1);
假设表t
有一个名为col1
的非二进制列,定义为CHAR(50) CHARACTER SET latin1
,但您希望将其转换为使用utf8mb4
,以便存储来自许多语言的值。以下语句可以实现这一目标:
ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET utf8mb4;
如果列包含不在两个字符集中的字符,则转换可能会有损失。
如果您有 MySQL 4.1 之前的旧表,其中一个非二进制列包含实际上是使用与服务器默认字符集不同的字符集编码的值,则会出现特殊情况。例如,一个应用程序可能已经在列中存储了sjis
值,尽管 MySQL 的默认字符集不同。可以将列转换为使用正确的字符集,但需要额外的步骤。假设服务器的默认字符集是latin1
,col1
被定义为CHAR(50)
,但其内容是sjis
值。第一步是将列转换为二进制数据类型,这将删除现有的字符集信息而不执行任何字符转换:
ALTER TABLE t MODIFY col1 BLOB;
下一步是将列转换为具有正确字符集的非二进制数据类型:
ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET sjis;
在将 MySQL 升级到 4.1 或更高版本后,此过程要求表在使用INSERT
或UPDATE
等语句修改之前未被修改。在这种情况下,MySQL 将使用latin1
存储新值在列中,并且该列将包含sjis
和latin1
值的混合,无法正确转换。
如果在创建列时指定了属性,那么在使用ALTER TABLE
修改表时也应该指定这些属性。例如,如果您指定了NOT NULL
和一个明确的DEFAULT
值,那么在ALTER TABLE
语句中也应该提供它们。否则,生成的列定义将不包括这些属性。
要转换表中的所有字符列,ALTER TABLE ... CONVERT TO CHARACTER SET *
charset*
语句可能会有用。请参阅第 15.1.9 节,“ALTER TABLE Statement”。
12.8 排序规则问题
12.8.1 在 SQL 语句中使用 COLLATE
12.8.2 COLLATE 子句的优先级
12.8.3 字符集和排序规则兼容性
12.8.4 表达式中的排序规则强制性
12.8.5 二进制排序规则与 _bin 排序规则的比较
12.8.6 排序规则效果示例
12.8.7 在 INFORMATION_SCHEMA 搜索中使用排序规则
以下各节讨论了字符集排序规则的各个方面。
12.8.1 在 SQL 语句中使用 COLLATE
使用COLLATE
子句,您可以覆盖比较的默认排序规则。COLLATE
可以在 SQL 语句的各个部分中使用。以下是一些示例:
-
在
ORDER BY
中:SELECT k FROM t1 ORDER BY k COLLATE latin1_german2_ci;
-
在
AS
中:SELECT k COLLATE latin1_german2_ci AS k1 FROM t1 ORDER BY k1;
-
在
GROUP BY
中:SELECT k FROM t1 GROUP BY k COLLATE latin1_german2_ci;
-
在聚合函数中:
SELECT MAX(k COLLATE latin1_german2_ci) FROM t1;
-
在
DISTINCT
中:SELECT DISTINCT k COLLATE latin1_german2_ci FROM t1;
-
在
WHERE
中:SELECT * FROM t1 WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;
SELECT * FROM t1 WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;
-
在
HAVING
中:SELECT k FROM t1 GROUP BY k HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;
12.8.2 COLLATE 子句优先级
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collate-precedence.html
COLLATE
子句具有很高的优先级(高于||
),因此以下两个表达式是等价的:
x || y COLLATE z
x || (y COLLATE z)
12.8.3 字符集和排序兼容性
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-compatibility.html
每个字符集都有一个或多个排序规则,但每个排序规则只与一个字符集相关联。因此,以下语句会导致错误消息,因为latin2_bin
排序规则与latin1
字符集不兼容:
mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid
for CHARACTER SET 'latin1'
12.8.4 表达式中的排序强制性
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-coercibility.html
在绝大多数语句中,MySQL 使用哪个排序来解决比较操作是显而易见的。例如,在以下情况下,应该清楚 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 分配强制性值如下:
-
明确的
COLLATE
子句具有强制性为 0(根本不可强制转换)。 -
具有不同排序的两个字符串的连接具有强制性为 1。
-
列或存储过程参数或局部变量的排序具有强制性为 2。
-
“系统常量”(由函数返回的字符串,如
USER()
或VERSION()
)具有强制性为 3。 -
文本常量的排序具有强制性为 4。
-
数值或时间值的排序具有强制性为 5。
-
NULL
或从NULL
派生的表达式具有强制性为 6。
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 使用字符集库的概念,有时可以用于确定字符集之间的子集关系,并使操作中的操作数转换为否则会产生错误的操作。参见 Section 12.2.1, “Character Set Repertoire”。
以下表格说明了前述规则的一些应用。
比较 | 使用的排序 |
---|---|
column1 = 'A' |
使用column1 的排序 |
column1 = 'A' COLLATE x |
使用'A' COLLATE x 的排序 |
column1 COLLATE x = 'A' COLLATE y |
错误 |
要确定字符串表达式的可强制性,使用COERCIBILITY()
函数(参见 Section 14.15, “Information Functions”):
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
系统变量确定字符集和排序的字符(非二进制)字符串。参见 Section 14.3, “Type Conversion in Expression Evaluation”。
12.8.5 二进制排序规则与 _bin 排序规则的比较
原文:
dev.mysql.com/doc/refman/8.0/en/charset-binary-collations.html
本节描述了二进制字符串的binary
排序规则与非二进制字符串的_bin
排序规则的比较。
使用BINARY
、VARBINARY
和BLOB
数据类型存储的二进制字符串具有名为binary
的字符集和排序规则。二进制字符串是字节序列,这些字节的数值确定了比较和排序顺序。参见第 12.10.8 节,“二进制字符集”。
使用CHAR
、VARCHAR
和TEXT
数据类型存储的非二进制字符串具有除binary
之外的字符集和排序规则。给定的非二进制字符集可以有多个排序规则,每个规则定义了集合中字符的特定比较和排序顺序。对于大多数字符集,其中一个是二进制排序规则,在排序规则名称中以_bin
后缀表示。例如,latin1
和big5
的二进制排序规则分别命名为latin1_bin
和big5_bin
。utf8mb4
是一个例外,它有两个二进制排序规则,分别是utf8mb4_bin
和utf8mb4_0900_bin
;参见第 12.10.1 节,“Unicode 字符集”。
binary
排序规则在几个方面与_bin
排序规则不同,将在以下部分讨论:
-
比较和排序的单位
-
字符集转换
-
大小写转换
-
比较中的尾随空格处理
-
插入和检索的尾随空格处理
比较和排序的单位
二进制字符串是字节序列。对于binary
校对规则,比较和排序基于数字字节值。非二进制字符串是字符序列,可能是多字节的。非二进制字符串的校对规则定义了用于比较和排序的字符值排序。对于_bin
校对规则,此排序基于数字字符代码值,类似于二进制字符串的排序,只是字符代码值可能是多字节的。
字符集转换
非二进制字符串具有一个字符集,并且在许多情况下会自动转换为另一个字符集,即使字符串具有_bin
校对规则:
-
将列值分配给具有不同字符集的另一列时:
UPDATE t1 SET utf8mb4_bin_column=latin1_column; INSERT INTO t1 (latin1_column) SELECT utf8mb4_bin_column FROM t2;
-
当使用字符串字面值为
INSERT
或UPDATE
分配列值时:SET NAMES latin1; INSERT INTO t1 (utf8mb4_bin_column) VALUES ('string-in-latin1');
-
从服务器发送结果到客户端时:
SET NAMES latin1; SELECT utf8mb4_bin_column FROM t2;
对于二进制字符串列,不会发生转换。对于类似的情况,字符串值会逐字节复制。
大小写转换
非二进制字符集的校对规则提供了关于字符大小写的信息,因此非二进制字符串中的字符可以从一个大小写转换为另一个大小写,即使是对于忽略大小写进行排序的_bin
校对规则:
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT LOWER('aA'), UPPER('zZ');
+-------------+-------------+
| LOWER('aA') | UPPER('zZ') |
+-------------+-------------+
| aa | ZZ |
+-------------+-------------+
字节中的大小写概念不适用于二进制字符串。要执行大小写转换,必须首先使用适合存储在字符串中的数据的字符集将字符串转换为非二进制字符串:
mysql> SET NAMES binary;
mysql> SELECT LOWER('aA'), LOWER(CONVERT('aA' USING utf8mb4));
+-------------+------------------------------------+
| LOWER('aA') | LOWER(CONVERT('aA' USING utf8mb4)) |
+-------------+------------------------------------+
| aA | aa |
+-------------+------------------------------------+
比较中处理末尾空格
MySQL 校对规则具有一个PAD SPACE
或NO PAD
的填充属性:
-
大多数 MySQL 校对规则具有
PAD SPACE
的填充属性。 -
基于 UCA 9.0.0 及更高版本的 Unicode 校对规则具有
NO PAD
的填充属性;参见第 12.10.1 节,“Unicode 字符集”。
对于非二进制字符串(CHAR
,VARCHAR
和TEXT
值),字符串校对填充属性决定了在比较末尾空格时的处理方式:
-
对于
PAD SPACE
校对规则,比较中末尾空格不重要;字符串比较时不考虑末尾空格。 -
NO PAD
校对规则将末尾空格视为比较中的重要字符,就像任何其他字符一样。
这些不同的行为可以使用两个utf8mb4
二进制校对规则来演示,其中一个是PAD SPACE
,另一个是NO PAD
。示例还展示了如何使用INFORMATION_SCHEMA
COLLATIONS
表来确定校对规则的填充属性。
mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE COLLATION_NAME LIKE 'utf8mb4%bin';
+------------------+---------------+
| COLLATION_NAME | PAD_ATTRIBUTE |
+------------------+---------------+
| utf8mb4_bin | PAD SPACE |
| utf8mb4_0900_bin | NO PAD |
+------------------+---------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 1 |
+------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_0900_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 0 |
+------------+
注意
在此上下文中的“比较”不包括LIKE
模式匹配运算符,对于这些运算符,无论校对规则如何,末尾空格都是重要的。
对于二进制字符串(BINARY
,VARBINARY
和BLOB
值),在比较中所有字节都是重要的,包括尾随空格:
mysql> SET NAMES binary;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 0 |
+------------+
插入和检索的尾随空格处理
CHAR(*
N*)
列存储长度为N
个字符的非二进制字符串。对于插入操作,长度小于N
个字符的值将用空格扩展。对于检索,尾随空格将被移除。
BINARY(*
N*)
列存储长度为N
字节的二进制字符串。对于插入操作,长度小于N
字节的值将用0x00
字节扩展。对于检索,不会删除任何内容;始终返回声明长度的值。
mysql> CREATE TABLE t1 (
a CHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
b BINARY(10)
);
mysql> INSERT INTO t1 VALUES ('x','x');
mysql> INSERT INTO t1 VALUES ('x ','x ');
mysql> SELECT a, b, HEX(a), HEX(b) FROM t1;
+------+------------------------+--------+----------------------+
| a | b | HEX(a) | HEX(b) |
+------+------------------------+--------+----------------------+
| x | 0x78000000000000000000 | 78 | 78000000000000000000 |
| x | 0x78200000000000000000 | 78 | 78200000000000000000 |
+------+------------------------+--------+----------------------+
12.8.6 排序规则效果示例
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-effect.html
示例 1:排序德语 Umlauts
假设表T
中的列X
具有这些latin1
列值:
Muffler
Müller
MX Systems
MySQL
还假设通过以下语句检索列值:
SELECT X FROM T ORDER BY X COLLATE *collation_name*;
使用不同排序规则的ORDER BY
,以下表格显示了值的排序结果。
latin1_swedish_ci |
latin1_german1_ci |
latin1_german2_ci |
---|---|---|
阻尼器 | 阻尼器 | 米勒 |
MX 系统 | 米勒 | 阻尼器 |
米勒 | MX 系统 | MX 系统 |
MySQL | MySQL | MySQL |
在这个例子中导致不同排序顺序的字符是ü
(德语“U-umlaut”)。
-
第一列显示了使用瑞典/芬兰排序规则的
SELECT
的结果,该规则表示 U-umlaut 与 Y 排序。 -
第二列显示了使用德国 DIN-1 规则的
SELECT
的结果,该规则表示 U-umlaut 与 U 排序。 -
第三列显示了使用德国 DIN-2 规则的
SELECT
的结果,该规则表示 U-umlaut 与 UE 排序。
示例 2:搜索德语 Umlauts
假设您有三个仅由字符集和排序规则不同的表:
mysql> SET NAMES utf8mb4;
mysql> CREATE TABLE german1 (
c CHAR(10)
) CHARACTER SET latin1 COLLATE latin1_german1_ci;
mysql> CREATE TABLE german2 (
c CHAR(10)
) CHARACTER SET latin1 COLLATE latin1_german2_ci;
mysql> CREATE TABLE germanutf8 (
c CHAR(10)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
每个表包含两条记录:
mysql> INSERT INTO german1 VALUES ('Bar'), ('Bär');
mysql> INSERT INTO german2 VALUES ('Bar'), ('Bär');
mysql> INSERT INTO germanutf8 VALUES ('Bar'), ('Bär');
上述排序规则中有两个具有A = Ä
的相等性,一个没有这种相等性(latin1_german2_ci
)。因此,比较产生了这里显示的结果:
mysql> SELECT * FROM german1 WHERE c = 'Bär';
+------+
| c |
+------+
| Bar |
| Bär |
+------+
mysql> SELECT * FROM german2 WHERE c = 'Bär';
+------+
| c |
+------+
| Bär |
+------+
mysql> SELECT * FROM germanutf8 WHERE c = 'Bär';
+------+
| c |
+------+
| Bar |
| Bär |
+------+
这不是一个错误,而是latin1_german1_ci
和utf8mb4_unicode_ci
的排序属性的结果(所示的排序是根据德国 DIN 5007 标准进行的)。
12.8.7 在 INFORMATION_SCHEMA 搜索中使用排序规则
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-information-schema.html
INFORMATION_SCHEMA
表中的字符串列具有utf8mb3_general_ci
排序规则,这是不区分大小写的。但是,对于与文件系统中表示的对象对应的值,例如数据库和表,在INFORMATION_SCHEMA
字符串列中的搜索可以是区分大小写或不区分大小写,这取决于底层文件系统的特性和lower_case_table_names
系统变量设置。例如,如果文件系统区分大小写,则搜索可能是区分大小写的。本节描述了这种行为以及如何在必要时进行修改。
假设一个查询在SCHEMATA.SCHEMA_NAME
列中搜索test
数据库。在 Linux 上,文件系统区分大小写,因此SCHEMATA.SCHEMA_NAME
与'test'
的比较匹配,但与'TEST'
的比较不匹配:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'TEST';
Empty set (0.00 sec)
这些结果发生在将lower_case_table_names
系统变量设置为 0 时。将lower_case_table_names
设置为 1 或 2 会导致第二个查询返回与第一个查询相同(非空)的结果。
注意
禁止使用与服务器初始化时使用的设置不同的lower_case_table_names
设置启动服务器。
在 Windows 或 macOS 上,文件系统不区分大小写,因此比较匹配'test'
和'TEST'
:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'TEST';
+-------------+
| SCHEMA_NAME |
+-------------+
| TEST |
+-------------+
在这种情况下,lower_case_table_names
的值没有任何区别。
前面的行为发生是因为在搜索与文件系统中表示的对象对应的值时,utf8mb3_general_ci
排序规则不用于INFORMATION_SCHEMA
查询。
如果对INFORMATION_SCHEMA
列的字符串操作的结果与预期不符,则可以使用显式的COLLATE
子句来强制使用合适的排序规则(参见第 12.8.1 节,“在 SQL 语句中使用 COLLATE”)。例如,要执行不区分大小写的搜索,请在INFORMATION_SCHEMA
列名后使用COLLATE
:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME COLLATE utf8mb3_general_ci = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME COLLATE utf8mb3_general_ci = 'TEST';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
你也可以使用UPPER()
或LOWER()
函数:
WHERE UPPER(SCHEMA_NAME) = 'TEST'
WHERE LOWER(SCHEMA_NAME) = 'test'
尽管即使在具有区分大小写文件系统的平台上也可以执行不区分大小写的比较,如上所示,但这并不一定总是正确的做法。在这样的平台上,可能存在仅在大小写不同的名称的多个对象。例如,同时存在名为city
、CITY
和City
的表。考虑搜索是否应匹配所有这些名称或仅匹配一个,并相应地编写查询。以下比较中的第一个(使用utf8mb3_bin
)是区分大小写的;其他则不是:
WHERE TABLE_NAME COLLATE utf8mb3_bin = 'City'
WHERE TABLE_NAME COLLATE utf8mb3_general_ci = 'city'
WHERE UPPER(TABLE_NAME) = 'CITY'
WHERE LOWER(TABLE_NAME) = 'city'
在INFORMATION_SCHEMA
的字符串列中搜索引用INFORMATION_SCHEMA
本身的值时,会使用utf8mb3_general_ci
校对规则,因为INFORMATION_SCHEMA
是一个在文件系统中没有实际表示的“虚拟”数据库。例如,与SCHEMATA.SCHEMA_NAME
的比较会匹配'information_schema'
或'INFORMATION_SCHEMA'
,不受平台影响:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'information_schema';
+--------------------+
| SCHEMA_NAME |
+--------------------+
| information_schema |
+--------------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'INFORMATION_SCHEMA';
+--------------------+
| SCHEMA_NAME |
+--------------------+
| information_schema |
+--------------------+
12.9 Unicode 支持
12.9.1 utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
12.9.2 utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)
12.9.3 utf8 字符集(utf8mb3 的弃用别名)
12.9.4 ucs2 字符集(UCS-2 Unicode 编码)
12.9.5 utf16 字符集(UTF-16 Unicode 编码)
12.9.6 utf16le 字符集(UTF-16LE Unicode 编码)
12.9.7 utf32 字符集(UTF-32 Unicode 编码)
12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
Unicode 标准包括来自基本多语言平面(BMP)和超出 BMP 范围的补充字符。本节描述了 MySQL 中对 Unicode 的支持。有关 Unicode 标准本身的信息,请访问Unicode Consortium 网站。
BMP 字符具有以下特征:
-
它们的代码点值介于 0 和 65535 之间(或
U+0000
和U+FFFF
)。 -
它们可以使用 8、16 或 24 位(1 到 3 字节)的可变长度编码进行编码。
-
它们可以使用 16 位(2 字节)的固定长度编码进行编码。
-
它们几乎可以涵盖所有主要语言中的所有字符。
补充字符超出 BMP 范围:
-
它们的代码点值介于
U+10000
和U+10FFFF
之间。 -
对补充字符的 Unicode 支持需要具有超出 BMP 字符范围的范围的字符集,因此比 BMP 字符占用更多的空间(每个字符最多 4 个字节)。
用于编码 Unicode 数据的 UTF-8(8 位单元的 Unicode 转换格式)方法根据 RFC 3629 实现,描述了采用从一个到四个字节的编码序列的编码序列。UTF-8 的理念是使用不同长度的字节序列对各种 Unicode 字符进行编码:
-
基本拉丁字母、数字和标点符号使用一个字节。
-
大多数欧洲和中东文字母适合于 2 字节序列:扩展拉丁字母(带有颚化音符、长音符、重音符、重音符和其他重音符)、西里尔字母、希腊字母、亚美尼亚字母、希伯来字母、阿拉伯字母、叙利亚字母等。
-
韩文、中文和日文表意文字使用 3 字节或 4 字节序列。
MySQL 支持这些 Unicode 字符集:
-
utf8mb4
:使用每个字符 1 到 4 个字节的 Unicode 字符集的 UTF-8 编码。 -
utf8mb3
:使用每个字符 1 到 3 个字节的 Unicode 字符集的 UTF-8 编码。这个字符集在 MySQL 8.0 中已被弃用,你应该使用utf8mb4
。 -
utf8
:utf8mb3
的别名。在 MySQL 8.0 中,这个别名已被弃用;请改用utf8mb4
。预计在未来的版本中,utf8
将成为utf8mb4
的别名。 -
ucs2
:Unicode 字符集的 UCS-2 编码,每个字符使用两个字节。在 MySQL 8.0.28 中已弃用;您应该预期在将来的版本中删除对该字符集的支持。 -
utf16
:Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2
,但具有补充字符的扩展。 -
utf16le
:Unicode 字符集的 UTF-16LE 编码。类似于utf16
,但是小端序而不是大端序。 -
utf32
:Unicode 字符集的 UTF-32 编码,每个字符使用四个字节。
注意
utf8mb3
字符集已被弃用,您应该预期在将来的 MySQL 版本中将其删除。请改用utf8mb4
。utf8
目前是utf8mb3
的别名,但现在已被弃用,预计utf8
随后将成为对utf8mb4
的引用。从 MySQL 8.0.28 开始,在 Information Schema 表的列和 SQL SHOW
语句的输出中,utf8mb3
也会显示为utf8
的替代项。
另外,在 MySQL 8.0.30 中,所有使用utf8_
前缀的校对规则都将改名为utf8mb3_
。
为避免关于utf8
含义的歧义,考虑明确指定字符集引用为utf8mb4
。
表 12.2,“Unicode 字符集的一般特性”总结了 MySQL 支持的 Unicode 字符集的一般特性。
表 12.2 Unicode 字符集的一般特性
字符集 | 支持的字符 | 每个字符所需的存储空间 |
---|---|---|
utf8mb3 ,utf8 (已弃用) |
仅限 BMP | 1、2 或 3 字节 |
ucs2 |
仅限 BMP | 2 字节 |
utf8mb4 |
BMP 和补充 | 1、2、3 或 4 字节 |
utf16 |
BMP 和补充 | 2 或 4 字节 |
utf16le |
BMP 和补充 | 2 或 4 字节 |
utf32 |
BMP 和补充 | 4 字节 |
超出 BMP 范围的字符在转换为仅支持 BMP 字符的 Unicode 字符集(utf8mb3
或ucs2
)时会被视为REPLACEMENT CHARACTER
并转换为'?'
。
如果您使用支持补充字符且比仅支持 BMP 的utf8mb3
和ucs2
字符集“更宽”的字符集,您的应用程序可能存在潜在的不兼容性问题;请参阅第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。该部分还描述了如何将表从(3 字节)utf8mb3
转换为(4 字节)utf8mb4
,以及在这样做时可能适用的约束条件。
大多数 Unicode 字符集都有类似的排序规则集。例如,每个字符集都有一个丹麦排序规则,其名称分别为utf8mb4_danish_ci
、utf8mb3_danish_ci
(已弃用)、utf8_danish_ci
(已弃用)、ucs2_danish_ci
、utf16_danish_ci
和utf32_danish_ci
。唯一的例外是utf16le
,它只有两个排序规则。有关 Unicode 排序规则及其区分特性的信息,包括辅助字符的排序规则属性,请参阅第 12.10.1 节,“Unicode 字符集”。
MySQL 对于 UCS-2、UTF-16 和 UTF-32 的实现以大端字节顺序存储字符,并且在数值开头不使用字节顺序标记(BOM)。其他数据库系统可能使用小端字节顺序或者 BOM。在这种情况下,在这些系统和 MySQL 之间传输数据时需要执行数值转换。UTF-16LE 的实现是小端字节顺序。
MySQL 对于 UTF-8 数值不使用 BOM。
与服务器使用 Unicode 通信的客户端应该相应地设置客户端字符集(例如,通过发出SET NAMES 'utf8mb4'
语句)。有些字符集不能用作客户端字符集。尝试在SET NAMES
或SET CHARACTER SET
中使用它们会产生错误。请参阅不允许的客户端字符集。
以下章节提供了关于 MySQL 中 Unicode 字符集的额外细节。
12.9.1 utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb4.html
utf8mb4
字符集具有以下特点:
-
支持 BMP 和补充字符。
-
每个多字节字符最多需要四个字节。
utf8mb4
与仅支持 BMP 字符并且每个字符最多使用三个字节的utf8mb3
字符集形成对比:
-
对于 BMP 字符,
utf8mb4
和utf8mb3
具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf8mb4
需要四个字节来存储,而utf8mb3
根本无法存储该字符。当将utf8mb3
列转换为utf8mb4
时,您无需担心转换补充字符,因为根本没有。
utf8mb4
是utf8mb3
的超集,因此对于诸如以下连接操作,结果具有字符集utf8mb4
和utf8mb4_col
的排序规则:
SELECT CONCAT(utf8mb3_col, utf8mb4_col);
同样,WHERE
子句中的以下比较按照utf8mb4_col
的排序规则进行:
SELECT * FROM utf8mb3_tbl, utf8mb4_tbl
WHERE utf8mb3_tbl.utf8mb3_col = utf8mb4_tbl.utf8mb4_col;
关于与多字节字符集相关的数据类型存储信息,请参阅字符串类型存储要求。
12.9.2 utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)
译文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb3.html
utf8mb3
字符集具有以下特点:
-
仅支持 BMP 字符(不支持补充字符)
-
每个多字节字符最多需要三个字节。
使用 UTF-8 数据但需要支持补充字符的应用程序应该使用utf8mb4
而不是utf8mb3
(参见第 12.9.1 节,“utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)”)。
utf8mb3
和ucs2
中提供完全相同的字符集。也就是说,它们具有相同的 repertoire。
注意
MySQL 推荐的字符集是utf8mb4
。所有新应用程序应该使用utf8mb4
。
utf8mb3
字符集已被弃用。utf8mb3
将在 MySQL 8.0.x 及其后续 LTS 版本系列的生命周期中继续受支持,以及在 MySQL 8.0 中。
预计utf8mb3
将在 MySQL 的未来主要版本中被移除。
由于更改字符集可能是一个复杂且耗时的任务,您应该立即开始准备使用utf8mb4
来为新应用程序做好准备。有关转换使用 utfmb3 的现有应用程序的指导,请参见第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。
utf8mb3
可以在CHARACTER SET
子句中使用,而utf8mb3_*
collation_substring*
可以在COLLATE
子句中使用,其中collation_substring
是bin
、czech_ci
、danish_ci
、esperanto_ci
、estonian_ci
等。例如:
CREATE TABLE t (s1 CHAR(1)) CHARACTER SET utf8mb3;
SELECT * FROM t WHERE s1 COLLATE utf8mb3_general_ci = 'x';
DECLARE x VARCHAR(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_danish_ci;
SELECT CAST('a' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_czech_ci;
在 MySQL 8.0.29 之前,语句中的utf8mb3
实例会被转换为utf8
。在 MySQL 8.0.30 及更高版本中,情况相反,因此在SHOW CREATE TABLE
或SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS
或SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS
等语句中,用户会看到以utf8mb3
或utf8mb3_
为前缀的字符集或校对名称。
utf8mb3
在CHARACTER SET
子句以外的上下文中也是有效的(但已弃用)。例如:
mysqld --character-set-server=utf8mb3
SET NAMES 'utf8mb3'; /* and other SET statements that have similar effect */
SELECT _utf8mb3 'a';
有关与多字节字符集相关的数据类型存储的信息,请参见字符串类型存储要求。
12.9.3 utf8 字符集(utf8mb3 的弃用别名)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8.html
MySQL 过去曾将utf8
用作utf8mb3
字符集的别名,但现在已弃用此用法;在 MySQL 8.0 中,SHOW
语句和INFORMATION_SCHEMA
表的列显示为utf8mb3
。有关更多信息,请参见第 12.9.2 节,“utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)”。
注意
MySQL 推荐的字符集是utf8mb4
。所有新应用程序应该使用utf8mb4
。
utf8mb3
字符集已被弃用。utf8mb3
将在 MySQL 8.0.x 及其后续 LTS 版本系列的生命周期中继续受支持,以及在 MySQL 8.0 中。
预计utf8mb3
将在 MySQL 的未来主要版本中被移除。
由于更改字符集可能是一个复杂且耗时的任务,您应该立即开始准备使用utf8mb4
来为新应用程序做好准备。有关转换现有使用 utfmb3 的应用程序的指导,请参见第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。
12.9.4 ucs2
字符集(UCS-2 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-ucs2.html
注意
ucs2
字符集在 MySQL 8.0.28 中已被弃用;预计将在未来的 MySQL 版本中移除。请改用utf8mb4
。
在 UCS-2 中,每个字符由一个 2 字节的 Unicode 代码表示,最高有效字节在前。例如:LATIN CAPITAL LETTER A
的代码为0x0041
,存储为一个 2 字节序列:0x00 0x41
。CYRILLIC SMALL LETTER YERU
(Unicode 0x044B
)存储为一个 2 字节序列:0x04 0x4B
。有关 Unicode 字符及其代码,请参考Unicode Consortium website。
ucs2
字符集具有以下特点:
-
仅支持 BMP 字符(不支持补充字符)
-
使用固定长度的 16 位编码,每个字符需要两个字节。
12.9.5 utf16
字符集(UTF-16 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf16.html
utf16
字符集是ucs2
字符集的扩展,使其能够编码补充字符:
-
对于 BMP 字符,
utf16
和ucs2
具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf16
有一个特殊的序列来使用 32 位表示字符。这被称为“代理”机制:对于大于0xffff
的数字,取 10 位并将它们加到0xd800
,放入第一个 16 位字中,再取 10 位并将它们加到0xdc00
,放入下一个 16 位字中。因此,所有补充字符需要 32 位,其中前 16 位是介于0xd800
和0xdbff
之间的数字,后 16 位是介于0xdc00
和0xdfff
之间的数字。示例在 Unicode 4.0 文档的第15.5 代理区中。
因为utf16
支持代理而ucs2
不支持,只有在utf16
中才适用的有效性检查:您不能插入顶部代理而没有底部代理,反之亦然。例如:
INSERT INTO t (ucs2_column) VALUES (0xd800); /* legal */
INSERT INTO t (utf16_column)VALUES (0xd800); /* illegal */
对于技术上有效但不是真正 Unicode 的字符,没有有效性检查(即 Unicode 认为是“未分配代码点”或“私有使用”字符甚至“非法”字符,如0xffff
)。例如,由于U+F8FF
是苹果 Logo,这是合法的:
INSERT INTO t (utf16_column)VALUES (0xf8ff); /* legal */
这些字符不能期望对每个人都有相同的含义。
因为 MySQL 必须考虑最坏情况(一个字符需要四个字节),utf16
列或索引的最大长度仅为ucs2
列或索引的最大长度的一半。例如,MEMORY
表索引键的最大长度为 3072 字节,因此这些语句创建具有ucs2
和utf16
列的最长允许索引的表:
CREATE TABLE tf (s1 VARCHAR(1536) CHARACTER SET ucs2) ENGINE=MEMORY;
CREATE INDEX i ON tf (s1);
CREATE TABLE tg (s1 VARCHAR(768) CHARACTER SET utf16) ENGINE=MEMORY;
CREATE INDEX i ON tg (s1);
12.9.6 utf16le 字符集(UTF-16LE Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf16le.html
这与utf16
相同,但是采用小端序而不是大端序。
12.9.7 utf32 字符集(UTF-32 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf32.html
utf32
字符集是固定长度的(类似于ucs2
,不同于utf16
)。utf32
为每个字符使用 32 位,不同于ucs2
(每个字符使用 16 位),也不同于utf16
(某些字符使用 16 位,某些使用 32 位)。
utf32
占用的空间是ucs2
的两倍,比utf16
更多,但utf32
和ucs2
一样具有存储的优势:utf32
所需的字节数等于字符数乘以 4。此外,与utf16
不同,utf32
没有编码技巧,因此存储的值等于代码值。
为了展示后一种优势的用处,这里有一个示例,展示如何根据utf32
的代码值确定一个utf8mb4
的值:
/* Assume code value = 100cc LINEAR B WHEELED CHARIOT */
CREATE TABLE tmp (utf32_col CHAR(1) CHARACTER SET utf32,
utf8mb4_col CHAR(1) CHARACTER SET utf8mb4);
INSERT INTO tmp VALUES (0x000100cc,NULL);
UPDATE tmp SET utf8mb4_col = utf32_col;
SELECT HEX(utf32_col),HEX(utf8mb4_col) FROM tmp;
MySQL 对未分配的 Unicode 字符或专用区域字符的添加非常宽容。实际上,utf32
只有一个有效性检查:没有代码值可以大于0x10ffff
。例如,这是不合法的:
INSERT INTO t (utf32_column) VALUES (0x110000); /* illegal */
12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-conversion.html
本节描述了在utf8mb3
和utf8mb4
字符集之间转换字符数据时可能遇到的问题。
注意
本讨论主要集中在utf8mb3
和utf8mb4
之间的转换,但类似的原则也适用于ucs2
字符集与utf16
或utf32
等字符集之间的转换。
utf8mb3
和utf8mb4
字符集的区别如下:
-
utf8mb3
仅支持基本多文种平面(BMP)中的字符。utf8mb4
还支持位于 BMP 之外的补充字符。 -
utf8mb3
每个字符最多使用三个字节。utf8mb4
每个字符最多使用四个字节。
注意
本讨论提到utf8mb3
和utf8mb4
字符集名称,明确指代 3 字节和 4 字节 UTF-8 字符集数据。
从utf8mb3
转换为utf8mb4
的一个优势是,这使应用程序能够使用补充字符。一个权衡是这可能增加数据存储空间的需求。
在表内容方面,从utf8mb3
转换为utf8mb4
没有问题:
-
对于 BMP 字符,
utf8mb4
和utf8mb3
具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf8mb4
需要四个字节来存储它,而utf8mb3
根本无法存储该字符。当将utf8mb3
列转换为utf8mb4
时,您不必担心转换补充字符,因为根本没有。
在表结构方面,这些是主要的潜在不兼容性:
-
对于可变长度字符数据类型(
VARCHAR
和TEXT
类型),在utf8mb4
列中允许的最大字符长度比在utf8mb3
列中要少。 -
对于所有字符数据类型(
CHAR
、VARCHAR
和TEXT
类型),在utf8mb4
列中可以索引的最大字符数比在utf8mb3
列中要少。
因此,要将表从utf8mb3
转换为utf8mb4
,可能需要更改一些列或索引定义。
可以使用ALTER TABLE
将表从utf8mb3
转换为utf8mb4
。假设一个表具有这样的定义:
CREATE TABLE t1 (
col1 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL,
col2 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL
) CHARACTER SET utf8mb3;
以下语句将t1
转换为使用utf8mb4
:
ALTER TABLE t1
DEFAULT CHARACTER SET utf8mb4,
MODIFY col1 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
MODIFY col2 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
从utf8mb3
转换为utf8mb4
的关键在于列或索引键的最大长度在字节方面保持不变。因此,在字符方面较小,因为字符的最大长度为四个字节而不是三个字节。对于CHAR
、VARCHAR
和TEXT
数据类型,在转换 MySQL 表时,请注意以下问题:
-
检查所有
utf8mb3
列的定义,并确保其不超过存储引擎的最大长度。 -
检查所有
utf8mb3
列上的索引,并确保其不超过存储引擎的最大长度。有时,由于存储引擎的增强,最大长度可能会发生变化。
如果满足上述条件,则必须减少列或索引的定义长度,或者继续使用utf8mb3
而不是utf8mb4
。
以下是可能需要进行结构更改的一些示例:
-
一个
TINYTEXT
列最多可以容纳 255 个字节,因此可以容纳 85 个 3 字节或 63 个 4 字节字符。假设您有一个使用utf8mb3
但必须能够包含超过 63 个字符的TINYTEXT
列。除非还将数据类型更改为更长的类型,如TEXT
,否则无法将其转换为utf8mb4
。同样,如果要将非常长的
VARCHAR
列从utf8mb3
转换为utf8mb4
,可能需要将其更改为更长的TEXT
类型之一。 -
对于使用
COMPACT
或REDUNDANT
行格式的表,InnoDB
对于utf8mb3
或utf8mb4
列的最大索引长度为 767 个字节,因此对于分别最多可以索引 255 或 191 个字符的utf8mb3
或utf8mb4
列。如果您当前具有超过 191 个字符的utf8mb3
列索引,则必须索引较少数量的字符。在使用
COMPACT
或REDUNDANT
行格式的InnoDB
表中,这些列和索引定义是合法的:col1 VARCHAR(500) CHARACTER SET utf8mb3, INDEX (col1(255))
要改用
utf8mb4
,索引必须更小:col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))
注意
对于使用
COMPRESSED
或DYNAMIC
行格式的InnoDB
表,允许索引键前缀的长度超过 767 字节(最多 3072 字节)。使用这些行格式创建的表允许您为utf8mb3
或utf8mb4
列最多索引 1024 或 768 个字符。有关相关信息,请参见第 17.22 节,“InnoDB 限制”和 DYNAMIC 行格式。
前述类型的更改只有在您有非常长的列或索引时才可能需要。否则,您应该能够在不出现问题的情况下将表从utf8mb3
转换为utf8mb4
,如前所述使用ALTER TABLE
。
以下项目总结了其他潜在的不兼容性:
-
SET NAMES 'utf8mb4'
导致连接字符集使用 4 字节字符集。只要服务器不发送 4 字节字符,就不应该有问题。否则,期望每个字符接收最多三个字节的应用程序可能会出现问题。相反,期望发送 4 字节字符的应用程序必须确保服务器理解它们。 -
对于复制,如果要在源上使用支持补充字符的字符集,则所有副本必须也理解它们。
此外,请记住一个一般原则,即如果表在源和副本上有不同的定义,这可能导致意外结果。例如,在源上使用
utf8mb3
和在副本上使用utf8mb4
会导致最大索引键长度的差异,这样做是有风险的。
如果您已经转换为utf8mb4
、utf16
、utf16le
或utf32
,然后决定转换回utf8mb3
或ucs2
(例如,降级到 MySQL 的旧版本),则应考虑以下事项:
-
utf8mb3
和ucs2
数据应该没有问题。 -
服务器必须足够新,以识别引用正在转换的字符集的定义。
-
对于引用
utf8mb4
字符集的对象定义,您可以在降级之前使用mysqldump进行转储,编辑转储文件以将utf8mb4
实例更改为utf8
,然后在旧服务器中重新加载文件,只要数据中没有 4 字节字符。旧服务器在转储文件对象定义中看到utf8
,并创建使用(3 字节)utf8
字符集的新对象。
12.10 支持的字符集和排序规则
12.10.1 Unicode 字符集
12.10.2 西欧字符集
12.10.3 中欧字符集
12.10.4 南欧和中东字符集
12.10.5 波罗的海字符集
12.10.6 斯拉夫字符集
12.10.7 亚洲字符集
12.10.8 二进制字符集
本节指示了 MySQL 支持的字符集。每个相关字符集组都有一个子节。对于每个字符集,列出了可接受的排序规则。
要列出可用的字符集及其默认排序规则,请使用SHOW CHARACTER SET
语句或查询INFORMATION_SCHEMA
CHARACTER_SETS
表。例如:
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| binary | Binary pseudo charset | binary | 1 |
| cp1250 | Windows Central European | cp1250_general_ci | 1 |
| cp1251 | Windows Cyrillic | cp1251_general_ci | 1 |
| cp1256 | Windows Arabic | cp1256_general_ci | 1 |
| cp1257 | Windows Baltic | cp1257_general_ci | 1 |
| cp850 | DOS West European | cp850_general_ci | 1 |
| cp852 | DOS Central European | cp852_general_ci | 1 |
| cp866 | DOS Russian | cp866_general_ci | 1 |
| cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 |
| dec8 | DEC West European | dec8_swedish_ci | 1 |
| eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 |
| euckr | EUC-KR Korean | euckr_korean_ci | 2 |
| gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 |
| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
| geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 |
| greek | ISO 8859-7 Greek | greek_general_ci | 1 |
| hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 |
| hp8 | HP West European | hp8_english_ci | 1 |
| keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 |
| koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 |
| koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 |
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 |
| latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 |
| latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 |
| macce | Mac Central European | macce_general_ci | 1 |
| macroman | Mac West European | macroman_general_ci | 1 |
| sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 |
| swe7 | 7bit Swedish | swe7_swedish_ci | 1 |
| tis620 | TIS620 Thai | tis620_thai_ci | 1 |
| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |
| ujis | EUC-JP Japanese | ujis_japanese_ci | 3 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
+----------+---------------------------------+---------------------+--------+
对于一个字符集有多个排序规则的情况,可能不清楚哪个排序规则最适合特定应用程序。为了避免选择错误的排序规则,可以通过一些比较具有代表性的数据值来确保给定的排序规则对值进行排序的方式符合您的期望。
12.10.1 Unicode 字符集
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html
本节描述了 Unicode 字符集可用的排序规则及其区分特性。有关 Unicode 的一般信息,请参见第 12.9 节,“Unicode 支持”。
MySQL 支持多个 Unicode 字符集:
-
utf8mb4
: 使用每个字符一到四个字节的 Unicode 字符集的 UTF-8 编码。 -
utf8mb3
: 使用每个字符一到三个字节的 Unicode 字符集的 UTF-8 编码。此字符集在 MySQL 8.0 中已弃用,您应该改用utf8mb4
。 -
utf8
: 对utf8mb3
的别名。在 MySQL 8.0 中,此别名已被弃用;请改用utf8mb4
。预计在将来的版本中,utf8
将成为utf8mb4
的别名。 -
ucs2
: 使用每个字符两个字节的 Unicode 字符集的 UCS-2 编码。在 MySQL 8.0.28 中已弃用;您应该预期在将来的版本中删除对此字符集的支持。 -
utf16
: Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2
但具有用于补充字符的扩展。 -
utf16le
: Unicode 字符集的 UTF-16LE 编码。类似于utf16
但是小端序而不是大端序。 -
utf32
: 使用每个字符四个字节的 UTF-32 编码的 Unicode 字符集。
注意
utf8mb3
字符集已被弃用,您应该预期在将来的 MySQL 版本中将其移除。请改用utf8mb4
。utf8
目前是utf8mb3
的别名,但现在已被弃用,utf8
预计随后将成为utf8mb4
的引用。从 MySQL 8.0.28 开始,在 Information Schema 表的列和 SQL SHOW
语句的输出中,utf8mb3
也会显示为utf8
的替代项。
为了避免关于utf8
含义的歧义,考虑在字符集引用中明确指定utf8mb4
。
utf8mb4
、utf16
、utf16le
和utf32
支持基本多文种平面(BMP)字符和超出 BMP 范围的补充字符。utf8mb3
和ucs2
仅支持 BMP 字符。
大多数 Unicode 字符集都有一般排序规则(名称中带有_general
或没有语言说明符号),二进制排序规则(名称中带有_bin
),以及几种特定语言的排序规则(带有语言说明符号)。例如,对于utf8mb4
,utf8mb4_general_ci
和utf8mb4_bin
是其一般和二进制排序规则,而utf8mb4_danish_ci
是其特定语言之一的排序规则。
大多数字符集具有单一的二进制排序。utf8mb4
是一个例外,它有两个:utf8mb4_bin
和(从 MySQL 8.0.17 开始)utf8mb4_0900_bin
。这两个二进制排序具有相同的排序顺序,但通过它们的填充属性和排序权重特性进行区分。参见 排序填充属性 和 字符排序权重。
utf16le
的排序支持有限。唯一可用的排序是 utf16le_general_ci
和 utf16le_bin
。这些与 utf16_general_ci
和 utf16_bin
类似。
-
Unicode Collation Algorithm (UCA) 版本 版本")
-
排序填充属性
-
特定语言排序
-
_general_ci 与 _unicode_ci 排序
-
字符排序权重
-
杂项信息
Unicode Collation Algorithm (UCA) 版本
MySQL 根据 www.unicode.org/reports/tr10/
中描述的 Unicode Collation Algorithm (UCA) 实现 *
xxx*_unicode_ci
排序。该排序使用版本-4.0.0 UCA 权重键:www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt
。*
xxx*_unicode_ci
排序对 Unicode Collation Algorithm 仅有部分支持。某些字符不受支持,组合标记也没有完全支持。这影响到越南语、约鲁巴语和纳瓦霍语等语言。在字符串比较中,组合字符被视为与使用单个 Unicode 字符写的相同字符不同,并且这两个字符被认为具有不同的长度(例如,由 CHAR_LENGTH()
函数返回或在结果集元数据中返回)。
基于高于 4.0.0 的 UCA 版本的 Unicode 排序在排序名称中包含版本。例如:
-
utf8mb4_unicode_520_ci
基于 UCA 5.2.0 权重键 (www.unicode.org/Public/UCA/5.2.0/allkeys.txt
), -
utf8mb4_0900_ai_ci
基于 UCA 9.0.0 权重键 (www.unicode.org/Public/UCA/9.0.0/allkeys.txt
).
LOWER()
和UPPER()
函数根据其参数的校对执行大小写折叠。如果一个字符只有在 Unicode 版本高于 4.0.0 中才有大写和小写版本,则这些函数只会在参数校对使用足够高的 UCA 版本时转换该字符。
校对填充属性
基于 UCA 9.0.0 及更高版本的校对比基于 UCA 9.0.0 之前版本的校对更快。它们的填充属性也是NO PAD
,与基于 UCA 9.0.0 之前版本的校对中使用的PAD SPACE
相反。对于非二进制字符串的比较,NO PAD
校对将字符串末尾的空格视为任何其他字符(参见比较中的尾随空格处理)。
要确定校对的填充属性,请使用INFORMATION_SCHEMA
的COLLATIONS
表,该表具有PAD_ATTRIBUTE
列。例如:
mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE CHARACTER_SET_NAME = 'utf8mb4';
+----------------------------+---------------+
| COLLATION_NAME | PAD_ATTRIBUTE |
+----------------------------+---------------+
| utf8mb4_general_ci | PAD SPACE |
| utf8mb4_bin | PAD SPACE |
| utf8mb4_unicode_ci | PAD SPACE |
| utf8mb4_icelandic_ci | PAD SPACE |
...
| utf8mb4_0900_ai_ci | NO PAD |
| utf8mb4_de_pb_0900_ai_ci | NO PAD |
| utf8mb4_is_0900_ai_ci | NO PAD |
...
| utf8mb4_ja_0900_as_cs | NO PAD |
| utf8mb4_ja_0900_as_cs_ks | NO PAD |
| utf8mb4_0900_as_ci | NO PAD |
| utf8mb4_ru_0900_ai_ci | NO PAD |
| utf8mb4_ru_0900_as_cs | NO PAD |
| utf8mb4_zh_0900_as_cs | NO PAD |
| utf8mb4_0900_bin | NO PAD |
+----------------------------+---------------+
具有NO PAD
校对的非二进制字符串值(CHAR
,VARCHAR
和TEXT
)与其他校对在尾随空格方面有所不同。例如,'a'
和'a '
比较为不同的字符串,而不是相同的字符串。可以使用utf8mb4
的二进制校对来看到这一点。utf8mb4_bin
的填充属性是PAD SPACE
,而utf8mb4_0900_bin
的填充属性是NO PAD
。因此,涉及utf8mb4_0900_bin
的操作不会添加尾随空格,并且涉及具有尾随空格的字符串的比较可能会因为两种校对而有所不同:
mysql> CREATE TABLE t1 (c CHAR(10) COLLATE utf8mb4_bin);
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO t1 VALUES('a');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM t1 WHERE c = 'a ';
+------+
| c |
+------+
| a |
+------+
1 row in set (0.00 sec)
mysql> ALTER TABLE t1 MODIFY c CHAR(10) COLLATE utf8mb4_0900_bin;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t1 WHERE c = 'a ';
Empty set (0.00 sec)
语言特定的校对
如果仅基于 Unicode 校对算法(UCA)的排序对某种语言效果不佳,MySQL 会实现语言特定的 Unicode 校对。语言特定的校对是基于 UCA 的,具有额外的语言定制规则。此类规则的示例稍后在本节中出现。有关特定语言排序的问题,unicode.org
提供了通用语言环境数据存储库(CLDR)校对图表,网址为www.unicode.org/cldr/charts/30/collation/index.html
。
例如,非语言特定的utf8mb4_0900_ai_ci
和语言特定的utf8mb4_*
LOCALE*_0900_ai_ci
Unicode 校对具有以下特点:
-
校对基于 UCA 9.0.0 和 CLDR v30,是不区分重音和大小写的。这些特征在校对名称中用
_0900
,_ai
和_ci
表示。例外:utf8mb4_la_0900_ai_ci
不是基于 CLDR,因为古典拉丁语在 CLDR 中未定义。 -
校对适用于范围[U+0, U+10FFFF]中的所有字符。
-
如果排序规则不是特定于语言的,它会按照默认顺序(如下所述)对所有字符进行排序,包括补充字符。如果排序规则是特定于语言的,它会根据特定于语言的规则正确对该语言的字符进行排序,并对不属于该语言的字符按默认顺序排序。
-
默认情况下,排序规则根据 DUCET 表(默认 Unicode 排序元素表)中列出的代码点对字符进行排序,根据表中分配的权重值。排序规则根据 UCA 构造的隐式权重值对未在 DUCET 表中列出代码点的字符进行排序。
-
对于非特定于语言的排序规则,缩约序列中的字符被视为单独的字符。对于特定于语言的排序规则,缩约可能会改变字符的排序顺序。
包含在下表中显示的区域代码或语言名称的排序规则名称是特定于语言的排序规则。Unicode 字符集可能包括一个或多个这些语言的排序规则。
表 12.3 Unicode 排序语言标识符
语言 | 语言标识符 |
---|---|
波斯尼亚语 | bs |
保加利亚语 | bg |
中文 | zh |
古典拉丁语 | la 或 roman |
克罗地亚语 | hr 或 croatian |
捷克语 | cs 或 czech |
丹麦语 | da 或 danish |
世界语 | eo 或 esperanto |
爱沙尼亚语 | et 或 estonian |
加利西亚语 | gl |
德语电话簿排序 | de_pb 或 german2 |
匈牙利语 | hu 或 hungarian |
冰岛语 | is 或 icelandic |
日语 | ja |
拉脱维亚语 | lv 或 latvian |
立陶宛语 | lt 或 lithuanian |
蒙古语 | mn |
挪威语 / 书面挪威语 | nb |
挪威语 / 新挪威语 | nn |
波斯语 | persian |
波兰语 | pl 或 polish |
罗马尼亚语 | ro 或 romanian |
俄语 | ru |
塞尔维亚语 | sr |
僧伽罗语 | sinhala |
斯洛伐克语 | sk 或 slovak |
斯洛文尼亚语 | sl 或 slovenian |
现代西班牙语 | es 或 spanish |
传统西班牙语 | es_trad 或 spanish2 |
瑞典语 | sv 或 swedish |
土耳其语 | tr 或 turkish |
越南语 | vi 或 vietnamese |
语言 | 语言标识符 |
MySQL 8.0.30 及更高版本提供了保加利亚语排序规则 utf8mb4_bg_0900_ai_ci
和 utf8mb4_bg_0900_as_cs
。
克罗地亚排序规则专为以下克罗地亚字母定制:Č
、Ć
、Dž
、Đ
、Lj
、Nj
、Š
、Ž
。
MySQL 8.0.30 及更高版本为塞尔维亚语提供了 utf8mb4_sr_latn_0900_ai_ci
和 utf8mb4_sr_latn_0900_as_cs
排序规则,为波斯尼亚语提供了 utf8mb4_bs_0900_ai_ci
和 utf8mb4_bs_0900_as_cs
排序规则,当这些语言使用拉丁字母书写时。
从 MySQL 8.0.30 开始,MySQL 为挪���的两种主要变体提供了排序规则:对于书面挪威语,您可以使用 utf8mb4_nb_0900_ai_ci
和 utf8mb4_nb_0900_as_cs
;对于新挪威语,MySQL 现在提供了 utf8mb4_nn_0900_ai_ci
和 utf8mb4_nn_0900_as_cs
。
对于日语,utf8mb4
字符集包括utf8mb4_ja_0900_as_cs
和utf8mb4_ja_0900_as_cs_ks
校对。这两种校对都是区分重音和区分大小写的。utf8mb4_ja_0900_as_cs_ks
还区分假名,将片假名字符与平假名字符区分开,而utf8mb4_ja_0900_as_cs
将片假名和平假名字符视为排序相等。需要日语校对但不需要假名敏感性的应用程序可以使用utf8mb4_ja_0900_as_cs
以获得更好的排序性能。utf8mb4_ja_0900_as_cs
使用三个权重级别进行排序;utf8mb4_ja_0900_as_cs_ks
使用四个。
对于不区分重音的古典拉丁校对,I
和J
视为相等,U
和V
视为相等。I
和J
,以及U
和V
在基本字母级别上视为相等。换句话说,J
被视为带重音的I
,U
被视为带重音的V
。
MySQL 8.0.30 及更高版本提供了蒙古语的校对,使用西里尔字母书写,utf8mb4_mn_cyrl_0900_ai_ci
和utf8mb4_mn_cyrl_0900_as_cs
。
西班牙语校对适用于现代和传统西班牙语。对于两者,ñ
(n-tilde)是n
和o
之间的单独字母。此外,对于传统西班牙语,ch
是c
和d
之间的单独字母,ll
是l
和m
之间的单独字母。
传统西班牙语校对也可用于阿斯图里亚斯语和加利西亚语。从 MySQL 8.0.30 开始,MySQL 还为加利西亚语提供了utf8mb4_gl_0900_ai_ci
和utf8mb4_gl_0900_as_cs
校对(这些校对与utf8mb4_es_0900_ai_ci
和utf8mb4_es_0900_as_cs
相同)。
瑞典校对包括瑞典规则。例如,在瑞典语中,以下关系成立,这是德语或法语说话者所不期望的:
Ü = Y < Ö
_general_ci 与 _unicode_ci 校对
对于任何 Unicode 字符集,使用*
xxx*_general_ci
校对的操作比*
xxx*_unicode_ci
校对的操作更快。例如,utf8mb4_general_ci
校对的比较速度更快,但略微不够准确,比utf8mb4_unicode_ci
校对的比较速度更快。原因是utf8mb4_unicode_ci
支持映射,例如扩展;也就是说,当一个字符与其他字符的组合相等时。例如,在德语和其他一些语言中,ß
等于ss
。utf8mb4_unicode_ci
还支持缩写和可忽略字符。utf8mb4_general_ci
是一个不支持扩展、缩写或可忽略字符的传统校对。它只能在字符之间进行一对一的比较。
进一步说明,在utf8mb4_general_ci
和utf8mb4_unicode_ci
中以下相等性成立(对于比较或搜索的影响,请参阅第 12.8.6 节,“校对效果示例”):
Ä = A
Ö = O
Ü = U
校对规则之间的一个区别是对于utf8mb4_general_ci
是真实的:
ß = s
而对于支持德国 DIN-1 排序(也称为字典顺序)的utf8mb4_unicode_ci
是真实的:
ß = ss
如果使用utf8mb4_unicode_ci
的排序对某种语言不起作用,MySQL 会实现特定语言的 Unicode 校对规则。例如,utf8mb4_unicode_ci
适用于德语字典顺序和法语,因此不需要创建特殊的utf8mb4
校对规则。
utf8mb4_general_ci
对于德语和法语都是令人满意的,除了ß
等于s
,而不等于ss
。如果这对您的应用程序可接受,应该使用utf8mb4_general_ci
因为它更快。如果这不可接受(例如,如果需要德语字典顺序),应该使用utf8mb4_unicode_ci
因为它更准确。
如果需要德国 DIN-2(电话簿)排序,请使用utf8mb4_german2_ci
校对规则,它将以下字符集视为相等:
Ä = Æ = AE
Ö = Œ = OE
Ü = UE
ß = ss
utf8mb4_german2_ci
类似于latin1_german2_ci
,但后者不将Æ
视为等于AE
或Œ
视为等于OE
。对于德语字典顺序,没有对应于latin1_german_ci
的utf8mb4_german_ci
,因为utf8mb4_general_ci
已经足够。
字符排序权重
字符的排序权重确定如下:
-
对于除
_bin
(二进制)校对规则之外的所有 Unicode 校对规则,MySQL 执行表查找以找到字符的排序权重。 -
对于除
utf8mb4_0900_bin
之外的_bin
校对规则,权重基于代码点,可能会添加前导零字节。 -
对于
utf8mb4_0900_bin
,权重是utf8mb4
编码的字节。排序顺序与utf8mb4_bin
相同,但速度更快。
可以使用WEIGHT_STRING()
函数显示排序权重。(参见第 14.8 节,“字符串函数和运算符”。)如果校对规则使用权重查找表,但某个字符不在表中(例如,因为它是一个“新”字符),排序权重的确定变得更加复杂:
-
对于一般校对规则中的 BMP 字符(
*
xxx*_general_ci
),权重是代码点。 -
对于 UCA 校对规则中的 BMP 字符(例如
*
xxx*_unicode_ci
和特定语言的校对规则),应用以下算法:if (code >= 0x3400 && code <= 0x4DB5) base= 0xFB80; /* CJK Ideograph Extension */ else if (code >= 0x4E00 && code <= 0x9FA5) base= 0xFB40; /* CJK Ideograph */ else base= 0xFBC0; /* All other characters */ aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
结果是两个排序元素的序列,
aaaa
后跟bbbb
。例如:mysql> SELECT HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci)); +----------------------------------------------------------+ | HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci)) | +----------------------------------------------------------+ | FBC084CF | +----------------------------------------------------------+
因此,
U+04cf CYRILLIC SMALL LETTER PALOCHKA
(ӏ
)在所有 UCA 4.0.0 校对规则中都大于U+04c0 CYRILLIC LETTER PALOCHKA
(Ӏ
)。对于 UCA 5.2.0 校对规则,所有帕洛奇卡字符一起排序。 -
对于一般校对规则中的补充字符,权重是
0xfffd REPLACEMENT CHARACTER
的权重。对于 UCA 4.0.0 校对规则中的补充字符,它们的排序权重是0xfffd
。也就是说,对于 MySQL 来说,所有补充字符彼此相等,并且大于几乎所有 BMP 字符。使用 Deseret 字符和
COUNT(DISTINCT)
的示例:CREATE TABLE t (s1 VARCHAR(5) CHARACTER SET utf32 COLLATE utf32_unicode_ci); INSERT INTO t VALUES (0xfffd); /* REPLACEMENT CHARACTER */ INSERT INTO t VALUES (0x010412); /* DESERET CAPITAL LETTER BEE */ INSERT INTO t VALUES (0x010413); /* DESERET CAPITAL LETTER TEE */ SELECT COUNT(DISTINCT s1) FROM t;
结果为 2,因为在 MySQL
*
xxx*_unicode_ci
校对中,替换字符的权重为0x0dc6
,而 Deseret Bee 和 Deseret Tee 的权重均为0xfffd
。(如果使用utf32_general_ci
校对,则结果为 1,因为在该校对中,这三个字符的权重均为0xfffd
。)使用楔形文字字符和
WEIGHT_STRING()
的示例:/* The four characters in the INSERT string are 00000041 # LATIN CAPITAL LETTER A 0001218F # CUNEIFORM SIGN KAB 000121A7 # CUNEIFORM SIGN KISH 00000042 # LATIN CAPITAL LETTER B */ CREATE TABLE t (s1 CHAR(4) CHARACTER SET utf32 COLLATE utf32_unicode_ci); INSERT INTO t VALUES (0x000000410001218f000121a700000042); SELECT HEX(WEIGHT_STRING(s1)) FROM t;
结果为:
0E33 FFFD FFFD 0E4A
0E33
和0E4A
是 UCA 4.0.0 中的主要权重。FFFD
是 KAB 和 KISH 的权重。所有补充字符相等的规则并非最佳选择,但不会引起问题。这些字符非常罕见,因此很少出现多字符字符串完全由补充字符组成。在日本,由于补充字符是晦涩的汉字表意文字,典型用户无论如何都不在乎它们的顺序。如果您真的希望按照 MySQL 规则和其次按照代码点值对行进行排序,那很容易实现:
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin
-
对于基于高于 4.0.0 版本的 UCA 的补充字符(例如,
*
xxx*_unicode_520_ci
),补充字符不一定都具有相同的排序权重。有些具有来自 UCAallkeys.txt
文件的显式权重。其他根据此算法计算权重:aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
“按字符的代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅在utf16_bin
中出现,因为存在代理。
假设utf16_bin
(utf16
的二进制校对)是一种“逐字节”而不是“逐字符”进行二进制比较。如果是这样,那么utf16_bin
中字符的顺序将与utf8mb4_bin
中的顺序不同。例如,以下图表显示了两个罕见字符。第一个字符位于E000
-FFFF
范围内,因此大于代理但小于补充字符。第二个字符是一个补充字符。
Code point Character utf8mb4 utf16
---------- --------- ------- -----
0FF9D HALFWIDTH KATAKANA LETTER N EF BE 9D FF 9D
10384 UGARITIC LETTER DELTA F0 90 8E 84 D8 00 DF 84
图表中的两个字符按代码点值顺序排列,因为0xff9d
< 0x10384
。它们按utf8mb4
值顺序排列,因为0xef
< 0xf0
。但如果我们使用逐字节比较,它们按utf16
值顺序排列,因为0xff
> 0xd8
。
因此,MySQL 的utf16_bin
校对不是“逐字节”的。它是“按代码点”。当 MySQL 在utf16
中看到补充字符编码时,它会转换为字符的代码点值,然后进行比较。因此,utf8mb4_bin
和utf16_bin
具有相同的排序。这与 SQL:2008 标准对 UCS_BASIC 校对的要求一致:“UCS_BASIC 是一种校对,其排序完全由要排序的字符串中字符的 Unicode 标量值确定。它适用于 UCS 字符库。由于每个字符库都是 UCS 字符库的子集,因此 UCS_BASIC 校对可能适用于每个字符集。注 11:字符的 Unicode 标量值是将其代码点视为无符号整数。”
如果字符集是ucs2
,比较是逐字节的,但ucs2
字符串不应包含代理项。
其他信息
*
xxx*_general_mysql500_ci
校对保留了原始*
xxx*_general_ci
校对的 5.1.24 版本之前的排序,并允许升级用于在 MySQL 5.1.24 之前创建的表(Bug#27877)。
12.10.2 西欧字符集
西欧字符集涵盖大多数西欧语言,如法语、西班牙语、加泰罗尼亚语、巴斯克语、葡萄牙语、意大利语、阿尔巴尼亚语、荷兰语、德语、丹麦语、瑞典语、挪威语、芬兰语、法罗语、冰岛语、爱尔兰语、苏格兰语和英语。
-
ascii
(美国 ASCII)排序规则:-
ascii_bin
-
ascii_general_ci
(默认)
-
-
cp850
(DOS 西欧)排序规则:-
cp850_bin
-
cp850_general_ci
(默认)
-
-
dec8
(DEC 西欧)排序规则:-
dec8_bin
-
dec8_swedish_ci
(默认)
MySQL 8.0.28 中已弃用
dec
字符集;预计在后续 MySQL 版本中将删除对其的支持。 -
-
hp8
(HP 西欧)排序规则:-
hp8_bin
-
hp8_english_ci
(默认)
MySQL 8.0.28 中已弃用
hp8
字符集;预计在后续 MySQL 版本中将删除对其的支持。 -
-
latin1
(cp1252 西欧)排序规则:-
latin1_bin
-
latin1_danish_ci
-
latin1_general_ci
-
latin1_general_cs
-
latin1_german1_ci
-
latin1_german2_ci
-
latin1_spanish_ci
-
latin1_swedish_ci
(默认)
MySQL 的
latin1
与 Windows 的cp1252
字符集相同。这意味着它与官方的ISO 8859-1
或 IANA(互联网编号分配机构)latin1
相同,只是 IANAlatin1
将0x80
到0x9f
之间的代码点视为“未定义”,而cp1252
,因此 MySQL 的latin1
,为这些位置分配了字符。例如,0x80
是欧元符号。对于cp1252
中的“未定义”条目,MySQL 将0x81
转换为 Unicode0x0081
,0x8d
转换为0x008d
,0x8f
转换为0x008f
,0x90
转换为0x0090
,0x9d
转换为0x009d
。latin1_swedish_ci
排序规则是 MySQL 大多数客户可能使用的默认排序规则。尽管经常说它基于瑞典/芬兰排序规则,但也有瑞典人和芬兰人不同意这种说法。latin1_german1_ci
和latin1_german2_ci
排序规则基于 DIN-1 和 DIN-2 标准,其中 DIN 代表德国标准化学会(ANSI 的德国等效)。DIN-1 称为“字典排序”,DIN-2 称为“电话簿排序”。有关此在比较或进行搜索时的影响的示例,请参见第 12.8.6 节,“排序效果示例”。-
latin1_german1_ci
��字典)规则:Ä = A Ö = O Ü = U ß = s
-
latin1_german2_ci
(电话簿)规则:Ä = AE Ö = OE Ü = UE ß = ss
在
latin1_spanish_ci
排序规则中,ñ
(n-tilde)是n
和o
之间的一个独立字母。 -
-
macroman
(Mac 西欧)排序规则:-
macroman_bin
-
macroman_general_ci
(默认)
macroroman
在 MySQL 8.0.28 中已弃用;预计在后续 MySQL 版本中将删除对其的支持。 -
-
swe7
(7 位瑞典语)排序规则:-
swe7_bin
-
swe7_swedish_ci
(默认)
-
12.10.3 中欧字符集
MySQL 为捷克共和国、斯洛伐克、匈牙利、罗马尼亚、斯洛文尼亚、克罗地亚、波兰和塞尔维亚(拉丁文)使用的字符集提供了一些支持。
-
cp1250
(Windows 中欧)排序规则:-
cp1250_bin
-
cp1250_croatian_ci
-
cp1250_czech_cs
-
cp1250_general_ci
(默认) -
cp1250_polish_ci
-
-
cp852
(DOS 中欧)排序规则:-
cp852_bin
-
cp852_general_ci
(默认)
-
-
keybcs2
(DOS Kamenicky Czech-Slovak)排序规则:-
keybcs2_bin
-
keybcs2_general_ci
(默认)
-
-
latin2
(ISO 8859-2 中欧)排序规则:-
latin2_bin
-
latin2_croatian_ci
-
latin2_czech_cs
-
latin2_general_ci
(默认) -
latin2_hungarian_ci
-
-
macce
(Mac 中欧)排序规则:-
macce_bin
-
macce_general_ci
(默认)
macce
在 MySQL 8.0.28 中已被弃用;预计在随后的 MySQL 版本中将不再支持它。 -
12.10.4 南欧和中东字符集
MySQL 支持的南欧和中东字符集包括亚美尼亚语、阿拉伯语、格鲁吉亚语、希腊语、希伯来语和土耳其语。
-
armscii8
(ARMSCII-8 亚美尼亚语)排序规则:-
armscii8_bin
-
armscii8_general_ci
(默认)
-
-
cp1256
(Windows 阿拉伯语)排序规则:-
cp1256_bin
-
cp1256_general_ci
(默认)
-
-
geostd8
(GEOSTD8 格鲁吉亚语)排序规则:-
geostd8_bin
-
geostd8_general_ci
(默认)
-
-
greek
(ISO 8859-7 希腊语)排序规则:-
greek_bin
-
greek_general_ci
(默认)
-
-
hebrew
(ISO 8859-8 希伯来语)排序规则:-
hebrew_bin
-
hebrew_general_ci
(默认)
-
-
latin5
(ISO 8859-9 土耳其语)排序规则:-
latin5_bin
-
latin5_turkish_ci
(默认)
-
12.10.5 波罗的海字符集
波罗的海字符集涵盖爱沙尼亚语、拉脱维亚语和立陶宛语。
-
cp1257
(Windows 波罗的海)排序规则:-
cp1257_bin
-
cp1257_general_ci
(默认) -
cp1257_lithuanian_ci
-
-
latin7
(ISO 8859-13 波罗的海)排序规则:-
latin7_bin
-
latin7_estonian_cs
-
latin7_general_ci
(默认) -
latin7_general_cs
-
12.10.6 西里尔字母字符集
原文:
dev.mysql.com/doc/refman/8.0/en/charset-cyrillic-sets.html
西里尔字母字符集和排序规则适用于白俄罗斯语、保加利亚语、俄罗斯语、乌克兰语和塞尔维亚语(西里尔字母)。
-
cp1251
(Windows 西里尔字母)排序规则:-
cp1251_bin
-
cp1251_bulgarian_ci
-
cp1251_general_ci
(默认) -
cp1251_general_cs
-
cp1251_ukrainian_ci
-
-
cp866
(DOS 俄语)排序规则:-
cp866_bin
-
cp866_general_ci
(默认)
-
-
koi8r
(KOI8-R Relcom 俄语)排序规则:-
koi8r_bin
-
koi8r_general_ci
(默认)
-
-
koi8u
(KOI8-U 乌克兰语)排序规则:-
koi8u_bin
-
koi8u_general_ci
(默认)
-
12.10.7 亚洲字符集
12.10.7.1 cp932 字符集
12.10.7.2 gb18030 字符集
我们支持的亚洲字符集包括中文、日文、韩文和泰文。这些可能会比较复杂。例如,中文字符集必须允许成千上万种不同的字符。有关 cp932
和 sjis
字符集的更多信息,请参见第 12.10.7.1 节,“cp932 字符集”。有关支持中国国家标准 GB 18030 字符集的更多信息,请参见第 12.10.7.2 节,“gb18030 字符集”。
有关 MySQL 中支持亚洲字符集的一些常见问题和问题的答案,请参见第 A.11 节,“MySQL 8.0 FAQ: MySQL 中文、日文和韩文字符集”。
-
big5
(Big5 繁体中文) 校对规则:-
big5_bin
-
big5_chinese_ci
(默认)
-
-
cp932
(Windows 日文 SJIS) 校对规则:-
cp932_bin
-
cp932_japanese_ci
(默认)
-
-
eucjpms
(Windows 日文 UJIS) 校对规则:-
eucjpms_bin
-
eucjpms_japanese_ci
(默认)
-
-
euckr
(EUC-KR 韩文) 校对规则:-
euckr_bin
-
euckr_korean_ci
(默认)
-
-
gb2312
(GB2312 简体中文) 校对规则:-
gb2312_bin
-
gb2312_chinese_ci
(默认)
-
-
gbk
(GBK 简体中文) 校对规则:-
gbk_bin
-
gbk_chinese_ci
(默认)
-
-
gb18030
(中国国家标准 GB18030) 校对规则:-
gb18030_bin
-
gb18030_chinese_ci
(默认) -
gb18030_unicode_520_ci
-
-
sjis
(Shift-JIS 日文) 校对规则:-
sjis_bin
-
sjis_japanese_ci
(默认)
-
-
tis620
(TIS620 泰文) 校对规则:-
tis620_bin
-
tis620_thai_ci
(默认)
-
-
ujis
(EUC-JP 日文) 校对规则:-
ujis_bin
-
ujis_japanese_ci
(默认)
-
big5_chinese_ci
校对规则按笔画数排序。
12.10.7.1 cp932
字符集
为什么需要cp932
?
在 MySQL 中,sjis
字符集对应于 IANA 定义的Shift_JIS
字符集,支持 JIS X0201 和 JIS X0208 字符。(参见www.iana.org/assignments/character-sets
。)
然而,“SHIFT JIS”作为一个描述性术语的含义变得非常模糊,通常包括各种供应商定义的Shift_JIS
扩展。
例如,在日本 Windows 环境中使用的“SHIFT JIS”是Shift_JIS
的微软扩展,其确切名称为Microsoft Windows Codepage : 932
或cp932
。除了Shift_JIS
支持的字符外,cp932
还支持扩展字符,如 NEC 特殊字符、NEC 选定-IBM 扩展字符和 IBM 选定字符。
许多日本用户在使用这些扩展字符时遇到问题。这些问题源于以下因素:
-
MySQL 会自动转换字符集。
-
字符集使用 Unicode(
ucs2
)进行转换。 -
sjis
字符集不支持这些扩展字符的转换。 -
从所谓的“SHIFT JIS”到 Unicode 有几种转换规则,根据转换规则的不同,一些字符转换为 Unicode 的方式也不同。MySQL 仅支持其中一种规则(稍后描述)。
MySQL 的cp932
字符集旨在解决这些问题。
因为 MySQL 支持字符集转换,所以将 IANA 的Shift_JIS
和cp932
分开成两个不同的字符集非常重要,因为它们提供不同的转换规则。
cp932
与sjis
有何不同?
cp932
字符集与sjis
有以下不同:
-
cp932
支持 NEC 特殊字符、NEC 选定-IBM 扩展字符和 IBM 选定字符。 -
一些
cp932
字符有两个不同的代码点,两者都转换为相同的 Unicode 代码点。在从 Unicode 转换回cp932
时,必须选择其中一个代码点。对于这种“往返转换”,使用微软推荐的规则。(参见support.microsoft.com/kb/170559/EN-US/
。)转换规则如下:
-
如果字符同时在 JIS X 0208 和 NEC 特殊字符中,则使用 JIS X 0208 的代码点。
-
如果字符同时在 NEC 特殊字符和 IBM 选定字符中,则使用 NEC 特殊字符的代码点。
-
如果字符同时在 IBM 选定字符和 NEC 选定-IBM 扩展字符中,则使用 IBM 扩展字符的代码点。
msdn.microsoft.com/en-us/goglobal/cc305152.aspx
上显示的表提供了关于cp932
字符的 Unicode 值的信息。对于cp932
表中带有四位数值下字符的条目,该数字代表相应的 Unicode(ucs2
)编码。对于带有下划线的两位数值下字符的条目,存在以这两位数值开头的一系列cp932
字符值。点击这样的表条目会带您到一个页面,显示以这些数字开头的每个cp932
字符的 Unicode 值。以下链接非常重要。它们对应以下字符集的编码:
-
NEC 特殊字符(主字节
0x87
):https://msdn.microsoft.com/en-us/goglobal/gg674964
-
NEC 选定—IBM 扩展字符(主字节
0xED
和0xEE
):https://msdn.microsoft.com/en-us/goglobal/gg671837 https://msdn.microsoft.com/en-us/goglobal/gg671838
-
IBM 选定字符(主字节
0xFA
、0xFB
、0xFC
):https://msdn.microsoft.com/en-us/goglobal/gg671839 https://msdn.microsoft.com/en-us/goglobal/gg671840 https://msdn.microsoft.com/en-us/goglobal/gg671841
-
-
cp932
支持与eucjpms
结合使用的用户定义字符的转换,并解决了sjis
/ujis
转换的问题。详情请参考www.sljfaq.org/afaq/encodings.html
。
对于一些字符,sjis
和 cp932
的 ucs2
转换是不同的。以下表格展示了这些差异。
转换为 ucs2
:
sjis /cp932 值 |
sjis -> ucs2 转换 |
cp932 -> ucs2 转换 |
---|---|---|
5C | 005C | 005C |
7E | 007E | 007E |
815C | 2015 | 2015 |
815F | 005C | FF3C |
8160 | 301C | FF5E |
8161 | 2016 | 2225 |
817C | 2212 | FF0D |
8191 | 00A2 | FFE0 |
8192 | 00A3 | FFE1 |
81CA | 00AC | FFE2 |
sjis /cp932 值 |
sjis -> ucs2 转换 |
cp932 -> ucs2 转换 |
从 ucs2
转换:
ucs2 值 |
ucs2 -> sjis 转换 |
ucs2 -> cp932 转换 |
---|---|---|
005C | 815F | 5C |
007E | 7E | 7E |
00A2 | 8191 | 3F |
00A3 | 8192 | 3F |
00AC | 81CA | 3F |
2015 | 815C | 815C |
2016 | 8161 | 3F |
2212 | 817C | 3F |
2225 | 3F | 8161 |
301C | 8160 | 3F |
FF0D | 3F | 817C |
FF3C | 3F | 815F |
FF5E | 3F | 8160 |
FFE0 | 3F | 8191 |
FFE1 | 3F | 8192 |
FFE2 | 3F | 81CA |
ucs2 值 |
ucs2 -> sjis 转换 |
ucs2 -> cp932 转换 |
任何日文字符集的用户都应该注意使用 --character-set-client-handshake
(或 --skip-character-set-client-handshake
)会产生重要影响。请参阅 7.1.7 “服务器命令选项”。
12.10.7.2 gb18030 字符集
在 MySQL 中,gb18030
字符集对应于“中华人民共和国国家标准 GB 18030-2005:信息技术-中文编码字符集”,这是中华人民共和国的官方字符集。
MySQL gb18030 字符集的特点
-
支持 GB 18030-2005 标准定义的所有代码点。范围内未分配的代码点(GB+8431A439,GB+90308130)和(GB+E3329A36,GB+EF39EF39)被视为 '
?
'(0x3F)。未分配代码点的转换返回 '?
'。 -
支持对所有 GB18030 代码点进行 UPPER 和 LOWER 转换。还支持 Unicode 定义的大小写折叠(基于
CaseFolding-6.3.0.txt
)。 -
支持将数据转换为其他字符集和从其他字符集转换。
-
支持 SQL 语句,如
SET NAMES
。 -
支持比较
gb18030
字符串,以及gb18030
字符串与其他字符集的字符串之间的比较。如果字符串具有不同的字符集,则进行转换。还支持包含或忽略尾随空格的比较。 -
Unicode 中的专用使用区域(U+E000,U+F8FF)映射到
gb18030
。 -
Unicode(U+D800,U+DFFF)和 GB18030 之间没有映射。尝试转换此范围内的代码点将返回 '
?
'。 -
如果输入序列非法,则返回错误或警告。如果在
CONVERT()
中使用非法序列,则返回错误。否则,返回警告。 -
为了与
utf8mb3
和utf8mb4
保持一致,不支持对连字使用 UPPER。 -
使用
gb18030_unicode_520_ci
排序时,搜索连字也会匹配大写连字。 -
如果一个字符有多个大写字符,则选择的大写字符是其小写字符本身。
-
最小多字节长度为 1,最大为 4。字符集使用前 1 或 2 个字节确定序列的长度。
支持的排序规则
-
gb18030_bin
: 二进制排序。 -
gb18030_chinese_ci
: 默认排序规则,支持拼音。非中文字符的排序基于原始排序键的顺序。如果UPPER(ch)
存在,则原始排序键为GB(UPPER(ch))
。否则,原始排序键为GB(ch)
。中文字符根据 Unicode 公共区域数据存储库(CLDR 24)中定义的拼音排序进行排序。非中文字符在中文字符之前排序,除了GB+FE39FE39
,这是代码点最大值。 -
gb18030_unicode_520_ci
: Unicode 排序。如果需要确保连字正确排序,请使用此排序。
12.10.8 二进制字符集
binary
字符集是二进制字符串的字符集,即字节序列。binary
字符集有一个排序规则,也称为binary
。比较和排序基于数字字节值,而不是数字字符代码值(对于多字节字符,它们与数字字节值不同)。有关binary
字符集的binary
排序规则与非二进制字符集的_bin
排序规则之间的区别,请参见第 12.8.5 节,“与 _bin 排序规则相比的 binary 排序规则”。
对于binary
字符集,大小写和重音等效的概念不适用:
-
对于存储为二进制字符串的单字节字符,字符和字节边界相同,因此在比较中大小写和重音差异很重要。也就是说,
binary
排序是区分大小写和重音的。mysql> SET NAMES 'binary'; mysql> SELECT CHARSET('abc'), COLLATION('abc'); +----------------+------------------+ | CHARSET('abc') | COLLATION('abc') | +----------------+------------------+ | binary | binary | +----------------+------------------+ mysql> SELECT 'abc' = 'ABC', 'a' = 'ä'; +---------------+------------+ | 'abc' = 'ABC' | 'a' = 'ä' | +---------------+------------+ | 0 | 0 | +---------------+------------+
-
对于存储为二进制字符串的多字节字符,字符和字节边界不同。字符边界丢失,因此依赖于它们的比较是没有意义的。
要对二进制字符串执行大小写转换,首先将其转换为使用适合字符串中存储的数据的字符集的非二进制字符串:
mysql> SET @str = BINARY 'New York';
mysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));
+-------------+------------------------------------+
| LOWER(@str) | LOWER(CONVERT(@str USING utf8mb4)) |
+-------------+------------------------------------+
| New York | new york |
+-------------+------------------------------------+
要将字符串表达式转换为二进制字符串,以下构造是等效的:
BINARY *expr*
CAST(*expr* AS BINARY)
CONVERT(*expr* USING BINARY)
如果一个值是字符字符串文字,则可以使用_binary
介绍符将其指定为二进制字符串。例如:
_binary 'a'
_binary
介绍符也适用于十六进制文字和位值文字,但是不必要;这些文字默认为二进制字符串。
有关介绍符的更多信息,请参见第 12.3.8 节,“字符集介绍符”。
注意
在mysql客户端中,二进制字符串使用十六进制表示,具体取决于--binary-as-hex
的值。有关该选项的更多信息,请参见第 6.5.1 节,“mysql — MySQL 命令行客户端”。
12.11 字符集限制
原文:
dev.mysql.com/doc/refman/8.0/en/charset-restrictions.html
-
标识符存储在
mysql
数据库表(user
、db
等)中,使用utf8mb3
,但标识符只能包含基本多文种平面(BMP)中的字符。标识符中不允许使用补充字符。 -
ucs2
、utf16
、utf16le
和utf32
字符集有以下限制:-
不能将它们中的任何一个用作客户端字符集。参见不允许的客户端字符集。
-
目前无法使用
LOAD DATA
加载使用这些字符集的数据文件。 -
不能在使用任何这些字符集的列上创建
FULLTEXT
索引。但是,您可以在没有索引的情况下对该列执行IN BOOLEAN MODE
搜索。
-
-
REGEXP
和RLIKE
运算符以字节方式工作,因此它们不是多字节安全的,可能会在多字节字符集下产生意外结果。此外,这些运算符通过它们的字节值比较字符,即使给定的排序将它们视为相等,重音字符也可能不会被视为相等。
12.12 设置错误消息语言
原文:
dev.mysql.com/doc/refman/8.0/en/error-message-language.html
默认情况下,mysqld会以英语显示错误消息,但可以改为显示其他几种语言:捷克语、丹麦语、荷兰语、爱沙尼亚语、法语、德语、希腊语、匈牙利语、意大利语、日语、韩语、挪威语、挪威-纽约语、波兰语、葡萄牙语、罗马尼亚语、俄语、斯洛伐克语、西班牙语或瑞典语。这适用于服务器写入错误日志并发送给客户端的消息。
要选择服务器写入错误消息的语言,请按照本节中的说明操作。有关更改错误消息的字符集(而不是语言)的信息,请参阅第 12.6 节,“错误消息字符集”。有关配置错误日志的一般信息,请参阅第 7.4.2 节,“错误日志”。
服务器根据以下规则搜索错误消息文件:
-
它会在从两个系统变量值
lc_messages_dir
和lc_messages
构造的目录中查找文件,后者转换为语言名���。假设您使用以下命令启动服务器:mysqld --lc_messages_dir=/usr/share/mysql --lc_messages=fr_FR
在这种情况下,mysqld将区域
fr_FR
映射到语言french
,并在/usr/share/mysql/french
目录中查找错误文件。默认情况下,语言文件位于 MySQL 基目录下的
share/mysql/*
LANGUAGE*
目录中。 -
如果无法在刚刚描述的构造目录中找到消息文件,则服务器将忽略
lc_messages
值,并仅使用lc_messages_dir
值作为查找位置。 -
如果服务器找不到配置的消息文件,它会向错误日志写入一条消息以指示问题,并默认使用内置的英语消息。
lc_messages_dir
系统变量只能在服务器启动时设置,并且在运行时只有一个全局只读值。lc_messages
可以在服务器启动时设置,并且具有可以在运行时修改的全局和会话值。因此,服务器在运行时可以更改错误消息语言,每个客户端可以通过将其会话lc_messages
值设置为所需的区域名称来拥有自己的错误消息语言。例如,如果服务器使用fr_FR
区域设置来显示错误消息,客户端可以执行以下语句以接收英语错误消息:
SET lc_messages = 'en_US';
12.13 添加字符集
原文:
dev.mysql.com/doc/refman/8.0/en/adding-character-set.html
12.13.1 字符定义数组
12.13.2 复杂字符集的字符串排序支持
12.13.3 复杂字符集的多字节字符支持
本节讨论了向 MySQL 添加字符集的过程。正确的过程取决于字符集是简单还是复杂:
-
如果字符集不需要用于排序的特殊字符串排序例程,也不需要多字节字符支持,则它是简单的。
-
如果字符集需要这些功能中的任何一个,它就是复杂的。
例如,greek
和swe7
是简单字符集,而big5
和czech
是复杂字符集。
要使用以下说明,您必须具有 MySQL 源代码分发。在说明中,MYSET
代表您想要添加的字符集的名称。
-
向
sql/share/charsets/Index.xml
文件的MYSET
添加一个<charset>
元素。使用文件中现有内容作为添加新内容的指南。latin1
<charset>
元素的部分列表如下:<charset name="latin1"> <family>Western</family> <description>cp1252 West European</description> ... <collation name="latin1_swedish_ci" id="8" order="Finnish, Swedish"> <flag>primary</flag> <flag>compiled</flag> </collation> <collation name="latin1_danish_ci" id="15" order="Danish"/> ... <collation name="latin1_bin" id="47" order="Binary"> <flag>binary</flag> <flag>compiled</flag> </collation> ... </charset>
<charset>
元素必须列出字符集的所有排序规则。这些排序规则必须至少包括一个二进制排序规则和一个默认(主要)排序规则。默认排序规则通常使用general_ci
(通用,不区分大小写)后缀命名。二进制排序规则可能是默认排序规则,但通常它们是不同的。默认排序规则应该有一个primary
标志。二进制排序规则应该有一个binary
标志。您必须为每个排序规则分配一个唯一的 ID 号。ID 范围从 1024 到 2047 保留用于用户定义的排序规则。要找到当前使用的排序规则 ID 的最大值,请使用此查询:
SELECT MAX(ID) FROM INFORMATION_SCHEMA.COLLATIONS;
-
此步骤取决于您是添加简单字符集还是复杂字符集。简单字符集只需要一个配置文件,而复杂字符集需要定义排序函数、多字节函数或两者的 C 源文件。
对于简单字符集,创建一个配置文件,
*
MYSET*.xml
,描述字符集属性。将此文件创建在sql/share/charsets
目录中。您可以使用latin1.xml
的副本作为此文件的基础。文件的语法非常简单:-
注释写作普通的 XML 注释(
<!-- *
text* -->
)。 -
<map>
数组元素内的单词由任意数量的空格分隔。 -
<map>
数组元素内的每个单词必须是十六进制格式的数字。 -
<ctype>
元素的<map>
数组元素有 257 个单词。之后的其他<map>
数组元素有 256 个单词。参见第 12.13.1 节,“字符定义数组”。 -
对于
Index.xml
中字符集的<charset>
元素中列出的每个排序,*
MYSET*.xml
必须包含定义字符排序的<collation>
元素。
对于复杂字符集,创建一个描述字符集属性并定义支持操作所需的支持例程的 C 源文件:
-
在
strings
目录中创建文件ctype-*
MYSET*.c
。查看现有的ctype-*.c
文件(如ctype-big5.c
)以了解需要定义的内容。您的文件中的数组必须具有类似ctype_*
MYSET*
、to_lower_*
MYSET*
等的名称。这些对应于简单字符集的数组。参见第 12.13.1 节,“字符定义数组”。 -
对于
Index.xml
中字符集的<charset>
元素中列出的每个<collation>
元素,ctype-*
MYSET*.c
文件必须提供排序的实现。 -
如果字符集需要字符串排序函数,请参见第 12.13.2 节,“复杂字符集的字符串排序支持”。
-
如果字符集需要多字节字符支持,请参见第 12.13.3 节,“复杂字符集的多字节字符支持”。
-
-
修改配置信息。使用现有的配置信息作为为
MYSYS
添加信息的指南。此示例假定字符集具有默认和二进制排序,但如果MYSET
具有其他排序,则需要更多行。-
编辑
mysys/charset-def.c
,并“注册”新字符集的排序。将这些行添加到“声明”部分:
#ifdef HAVE_CHARSET_*MYSET* extern CHARSET_INFO my_charset_*MYSET*_general_ci; extern CHARSET_INFO my_charset_*MYSET*_bin; #endif
将这些行添加到“注册”部分:
#ifdef HAVE_CHARSET_*MYSET* add_compiled_collation(&my_charset_*MYSET*_general_ci); add_compiled_collation(&my_charset_*MYSET*_bin); #endif
-
如果字符集使用
ctype-*
MYSET*.c
,编辑strings/CMakeLists.txt
并将ctype-*
MYSET*.c
添加到STRINGS_SOURCES
变量的定义中。 -
编辑
cmake/character_sets.cmake
:-
将
MYSET
添加到CHARSETS_AVAILABLE
的值中,按字母顺序排列。 -
将
MYSET
按字母顺序添加到CHARSETS_COMPLEX
的值中。即使对于简单字符集也需要这样做,以便CMake可以识别-DDEFAULT_CHARSET=*
MYSET*
。
-
-
-
重新配置、重新编译并测试。
12.13.1 字符定义数组
每个简单字符集都有一个配置文件,位于 sql/share/charsets
目录中。 对于名为 MYSYS
的字符集,文件名为 *
MYSET*.xml
。 它使用 <map>
数组元素列出字符集属性。 <map>
元素出现在这些元素内部:
-
<ctype>
为每个字符定义属性。 -
<lower>
和<upper>
列出小写和大写字符。 -
<unicode>
将 8 位字符值映射到 Unicode 值。 -
<collation>
元素指示用于比较和排序的字符排序,每个排序一个元素。 二进制排序不需要<map>
元素,因为字符代码本身提供排序。
对于在 strings
目录中的 ctype-*
MYSET*.c
文件中实现的复杂字符集,有相应的数组:ctype_*
MYSET*[]
,to_lower_*
MYSET*[]
等等。 并非每个复杂字符集都有所有数组。 有关示例,请参见现有的 ctype-*.c
文件。 有关更多信息,请参见 strings
目录中的 CHARSET_INFO.txt
文件。
大多数数组按字符值索引,并具有 256 个元素。 <ctype>
数组按字符值 + 1 索引,并具有 257 个元素。 这是处理 EOF
的传统约定。
<ctype>
数组元素是位值。 每个元素描述字符集中单个字符的属性。 每个属性与位掩码关联,如 include/m_ctype.h
中定义的:
#define _MY_U 01 /* Upper case */
#define _MY_L 02 /* Lower case */
#define _MY_NMR 04 /* Numeral (digit) */
#define _MY_SPC 010 /* Spacing character */
#define _MY_PNT 020 /* Punctuation */
#define _MY_CTR 040 /* Control character */
#define _MY_B 0100 /* Blank */
#define _MY_X 0200 /* heXadecimal digit */
给定字符的 <ctype>
值应该是描述该字符的适用位掩码值的并集。 例如,'A'
是大写字符(_MY_U
)以及十六进制数字(_MY_X
),因此其 ctype
值应该定义如下:
ctype['A'+1] = _MY_U | _MY_X = 01 | 0200 = 0201
m_ctype.h
中的位掩码值是八进制值,但在 *
MYSET*.xml
中的 <ctype>
数组的元素应该以十六进制值编写。
<lower>
和 <upper>
数组保存与字符集中每个成员对应的小写和大写字符。 例如:
lower['A'] should contain 'a'
upper['a'] should contain 'A'
每个 <collation>
数组指示字符应如何排序以进行比较和排序。 MySQL 根据此信息的值对字符进行排序。 在某些情况下,这与 <upper>
数组相同,这意味着排序不区分大小写。 对于更复杂的排序规则(用于复杂字符集),请参阅 12.13.2 “复杂字符集的字符串排序支持” 中有关字符串排序的讨论。
12.13.2 复杂字符集的字符串排序支持
对于一个名为MYSET
的简单字符集,排序规则在*
MYSET*.xml
配置文件中使用<collation>
元素内的<map>
数组元素指定。如果你的语言的排序规则过于复杂,无法用简单的数组处理,你必须在strings
目录中的ctype-*
MYSET*.c
源文件中定义字符串排序函数。
现有的字符集提供了最好的文档和示例,展示了这些函数是如何实现的。查看strings
目录中的ctype-*.c
文件,比如big5
、czech
、gbk
、sjis
和tis160
字符集的文件。查看MY_COLLATION_HANDLER
结构体,了解它们是如何使用的。另请参阅strings
目录中的CHARSET_INFO.txt
文件获取更多信息。
12.13.3 复杂字符集的多字节字符支持
原文:
dev.mysql.com/doc/refman/8.0/en/multibyte-characters.html
如果您想要为一个名为MYSET
的新字符集添加多字节字符支持,您必须在strings
目录中的ctype-*
MYSET*.c
源文件中使用多字节字符函数。
现有的字符集提供了最佳的文档和示例,展示了这些函数是如何实现的。查看strings
目录中的ctype-*.c
文件,例如euc_kr
、gb2312
、gbk
、sjis
和ujis
字符集的文件。查看MY_CHARSET_HANDLER
结构以了解它们的使用方式。另请参阅strings
目录中的CHARSET_INFO.txt
文件获取更多信息。
12.14 向字符集添加排序
12.14.1 排序实现类型
12.14.2 选择排序 ID
12.14.3 向 8 位字符集添加简单排序
12.14.4 向 Unicode 字符集添加 UCA 排序
警告
用户定义的排序已被弃用;您应该期望在将来的 MySQL 版本中删除对它们的支持。从 MySQL 8.0.33 开始,服务器对任何 SQL 语句中使用 COLLATE *
user_defined_collation*
都会发出警告;当服务器以 --collation-server
设置为用户定义排序的名称启动时,也会发出警告。
排序是一组定义如何比较和排序字符串的规则。MySQL 中的每个排序都属于单个字符集。每个字符集至少有一个排序,大多数有两个或更多排序。
字符串排序是基于权重的。字符集中的每个字符都映射到一个权重。具有相同权重的字符比较相等,具有不同权重的字符根据其权重的相对大小进行比较。
WEIGHT_STRING()
函数可用于查看字符串中字符的权重。它返回的表示权重的值是一个二进制字符串,因此方便使用 HEX(WEIGHT_STRING(*
str*))
以可打印形式显示权重。以下示例显示,如果是非二进制不区分大小写字符串,则对于 'AaBb'
中的字母,权重不会有区别,但如果是二进制字符串,则会有区别:
mysql> SELECT HEX(WEIGHT_STRING('AaBb' COLLATE latin1_swedish_ci));
+------------------------------------------------------+
| HEX(WEIGHT_STRING('AaBb' COLLATE latin1_swedish_ci)) |
+------------------------------------------------------+
| 41414242 |
+------------------------------------------------------+
mysql> SELECT HEX(WEIGHT_STRING(BINARY 'AaBb'));
+-----------------------------------+
| HEX(WEIGHT_STRING(BINARY 'AaBb')) |
+-----------------------------------+
| 41614262 |
+-----------------------------------+
MySQL 支持多种排序实现,如 第 12.14.1 节“排序实现类型” 中讨论的。其中一些可以在不重新编译 MySQL 的情况下添加:
-
8 位字符集的简单排序。
-
基于 UCA 的 Unicode 字符集排序。
-
二进制 (
*
xxx*_bin
) 排序。
以下部分描述如何向现有字符集添加前两种类型的用户定义排序。所有现有字符集已经有一个二进制排序,因此这里不需要描述如何添加一个。
警告
不支持重新定义内置排序,并可能导致意外的服务器行为。
添加新用户定义排序的步骤摘要:
-
选择一个排序 ID。
-
添加配置信息,命名排序规则并描述字符排序规则。
-
重新启动服务器。
-
确保服务器识别排序。
此处的说明仅涵盖可以在不重新编译 MySQL 的情况下添加的用户定义排序规则。要添加需要重新编译的排序规则(通过在 C 源文件中使用函数实现),请使用第 12.13 节的说明,“添加字符集”。但是,不要添加完整字符集所需的所有信息,只需修改现有字符集的适当文件。也就是说,根据当前字符集的排序规则已有的内容,为新的排序规则添加数据结构、函数和配置信息。
注意
如果您修改现有的用户定义排序规则,可能会影响使用该排序规则的列索引的行排序。在这种情况下,重新构建任何此类索引以避免问题,如查询结果不正确。请参见第 3.14 节,“重建或修复表或索引”。
附加资源
-
示例显示如何为全文搜索添加排序规则:第 14.9.7 节,“为全文索引添加用户定义排序规则”
-
Unicode 排序算法(UCA)规范:
www.unicode.org/reports/tr10/
-
本地化数据标记语言(LDML)规范:
www.unicode.org/reports/tr35/
12.14.1 整理实现类型
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-implementations.html
MySQL 实现了几种类型的整理:
8 位字符集的简单整理
这种整理使用一个包含 256 个权重的数组来实现,定义了从字符代码到权重的一对一映射。latin1_swedish_ci
是一个例子。它是一个不区分大小写的整理,因此字符的大写和小写版本具有相同的权重,它们比较相等。
mysql> SET NAMES 'latin1' COLLATE 'latin1_swedish_ci';
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT HEX(WEIGHT_STRING('a')), HEX(WEIGHT_STRING('A'));
+-------------------------+-------------------------+
| HEX(WEIGHT_STRING('a')) | HEX(WEIGHT_STRING('A')) |
+-------------------------+-------------------------+
| 41 | 41 |
+-------------------------+-------------------------+
1 row in set (0.01 sec)
mysql> SELECT 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
| 1 |
+-----------+
1 row in set (0.12 sec)
有关实现说明,请参见第 12.14.3 节,“向 8 位字符集添加简单整理”。
8 位字符集的复杂整理
这种整理使用 C 源文件中的函数来定义如何对字符进行排序,如第 12.13 节,“添加字符集”中所述。
非 Unicode 多字节字符集的整理
对于这种类型的整理,8 位(单字节)和多字节字符的处理方式不同。对于 8 位字符,字符代码以不区分大小写的方式映射到权重。(例如,单字节字符'a'
和'A'
都具有权重0x41
。)对于多字节字符,字符代码和权重之间有两种关系:
-
权重等于字符代码。
sjis_japanese_ci
是这种整理的一个例子。多字节字符'ぢ'
的字符代码为0x82C0
,权重也是0x82C0
。mysql> CREATE TABLE t1 (c1 VARCHAR(2) CHARACTER SET sjis COLLATE sjis_japanese_ci); Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO t1 VALUES ('a'),('A'),(0x82C0); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1; +------+---------+------------------------+ | c1 | HEX(c1) | HEX(WEIGHT_STRING(c1)) | +------+---------+------------------------+ | a | 61 | 41 | | A | 41 | 41 | | ぢ | 82C0 | 82C0 | +------+---------+------------------------+ 3 rows in set (0.00 sec)
-
字符代码一对一映射到权重,但代码不一定等于权重。
gbk_chinese_ci
是这种整理的一个例子。多字节字符'膰'
的字符代码为0x81B0
,但权重为0xC286
。mysql> CREATE TABLE t1 (c1 VARCHAR(2) CHARACTER SET gbk COLLATE gbk_chinese_ci); Query OK, 0 rows affected (0.33 sec) mysql> INSERT INTO t1 VALUES ('a'),('A'),(0x81B0); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1; +------+---------+------------------------+ | c1 | HEX(c1) | HEX(WEIGHT_STRING(c1)) | +------+---------+------------------------+ | a | 61 | 41 | | A | 41 | 41 | | 膰 | 81B0 | C286 | +------+---------+------------------------+ 3 rows in set (0.00 sec)
有关实现说明,请参见第 12.13 节,“添加字符集”。
Unicode 多字节字符集的整理
这些整理中有一些基于 Unicode 整理算法(UCA),而其他一些则不是。
非 UCA 整理将字符代码一对一映射到权重。在 MySQL 中,这种整理不区分大小写,也不区分重音。utf8mb4_general_ci
是一个例子:'a'
、'A'
、'À'
和'á'
每个具有不同的字符代码,但都具有权重0x0041
,并且比较相等。
mysql> SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t1
(c1 CHAR(1) CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t1 VALUES ('a'),('A'),('À'),('á');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1;
+------+---------+------------------------+
| c1 | HEX(c1) | HEX(WEIGHT_STRING(c1)) |
+------+---------+------------------------+
| a | 61 | 0041 |
| A | 41 | 0041 |
| À | C380 | 0041 |
| á | C3A1 | 0041 |
+------+---------+------------------------+
4 rows in set (0.00 sec)
MySQL 中基于 UCA 的整理具有以下特性:
-
如果一个字符有权重,每个权重使用 2 个字节(16 位)。
-
一个字符可能有零个权重(或空权重)。在这种情况下,该字符是可忽略的。例如:"U+0000 NULL"没有权重,是可忽略的。
-
一个字符可能有一个权重。例如:
'a'
的权重为0x0E33
。mysql> SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'; Query OK, 0 rows affected (0.05 sec) mysql> SELECT HEX('a'), HEX(WEIGHT_STRING('a')); +----------+-------------------------+ | HEX('a') | HEX(WEIGHT_STRING('a')) | +----------+-------------------------+ | 61 | 0E33 | +----------+-------------------------+ 1 row in set (0.02 sec)
-
一个字符可能有多个权重。这是一个扩展。例如:德语字母
'ß'
(SZ 连字,或 SHARP S)的权重为0x0FEA0FEA
。mysql> SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'; Query OK, 0 rows affected (0.11 sec) mysql> SELECT HEX('ß'), HEX(WEIGHT_STRING('ß')); +-----------+--------------------------+ | HEX('ß') | HEX(WEIGHT_STRING('ß')) | +-----------+--------------------------+ | C39F | 0FEA0FEA | +-----------+--------------------------+ 1 row in set (0.00 sec)
-
多个字符可能有一个权重。这是一个收缩。例如:
'ch'
是捷克语中的一个字母,权重为0x0EE2
。mysql> SET NAMES 'utf8mb4' COLLATE 'utf8mb4_czech_ci'; Query OK, 0 rows affected (0.09 sec) mysql> SELECT HEX('ch'), HEX(WEIGHT_STRING('ch')); +-----------+--------------------------+ | HEX('ch') | HEX(WEIGHT_STRING('ch')) | +-----------+--------------------------+ | 6368 | 0EE2 | +-----------+--------------------------+ 1 row in set (0.00 sec)
也可能存在多字符对多权重的映射(这是扩展与收缩),但 MySQL 不支持。
对于非 UCA 排序的实现说明,请参见第 12.13 节,“添加字符集”。对于 UCA 排序,请参见第 12.14.4 节,“向 Unicode 字符集添加 UCA 排序”。
杂项排序
还有一些排序不属于前述任何类别。
12.14.2 选择排序规则 ID
原文:
dev.mysql.com/doc/refman/8.0/en/adding-collation-choosing-id.html
每个排序规则必须有一个唯一的 ID。要添加排序规则,必须选择一个当前未使用的 ID 值。MySQL 支持两字节的排序规则 ID。ID 范围从 1024 到 2047 保留给用户定义的排序规则。
你选择的排序规则 ID 出现在以下情境中:
-
信息模式
COLLATIONS
表的ID
列。 -
SHOW COLLATION
输出的Id
列。 -
MYSQL_FIELD
C API 数据结构的charsetnr
成员。 -
mysql_get_character_set_info()
C API 函数返回的MY_CHARSET_INFO
数据结构的number
成员。
要确定当前使用的最大 ID,请执行以下语句:
mysql> SELECT MAX(ID) FROM INFORMATION_SCHEMA.COLLATIONS;
+---------+
| MAX(ID) |
+---------+
| 247 |
+---------+
要显示所有当前使用的 ID 列表,请执行此语句:
mysql> SELECT ID FROM INFORMATION_SCHEMA.COLLATIONS ORDER BY ID;
+-----+
| ID |
+-----+
| 1 |
| 2 |
| ... |
| 52 |
| 53 |
| 57 |
| 58 |
| ... |
| 98 |
| 99 |
| 128 |
| 129 |
| ... |
| 247 |
+-----+
警告
在升级之前,应保存更改的配置文件。如果在原地升级,该过程将替换修改过的文件。
12.14.3 向 8 位字符集添加简单排序规则
原文:
dev.mysql.com/doc/refman/8.0/en/adding-collation-simple-8bit.html
本节描述了如何通过在 MySQL 的Index.xml
文件中编写与<charset>
字符集描述相关联的<collation>
元素来为 8 位字符集添加简单排序规则的过程。这里描述的过程不需要重新编译 MySQL。示例将一个名为latin1_test_ci
的排序规则添加到latin1
字符集中。
-
选择一个排序规则 ID,如第 12.14.2 节“选择排序规则 ID”所示。以下步骤使用 ID 为 1024。
-
修改
Index.xml
和latin1.xml
配置文件。这些文件位于由character_sets_dir
系统变量命名的目录中。您可以按照以下方式检查变量值,尽管在您的系统上路径名可能不同:mysql> SHOW VARIABLES LIKE 'character_sets_dir'; +--------------------+-----------------------------------------+ | Variable_name | Value | +--------------------+-----------------------------------------+ | character_sets_dir | /user/local/mysql/share/mysql/charsets/ | +--------------------+-----------------------------------------+
-
为排序规则选择一个名称,并在
Index.xml
文件中列出。找到正在添加排序规则的字符集的<charset>
元素,并添加一个<collation>
元素,指示排序规则名称和 ID,以将名称与 ID 关联起来。例如:<charset name="latin1"> ... <collation name="latin1_test_ci" id="1024"/> ... </charset>
-
在
latin1.xml
配置文件中,添加一个命名排序规则的<collation>
元素,并包含一个<map>
元素,为字符代码 0 到 255 定义一个字符代码到权重映射表。<map>
元素中的每个值必须是十六进制格式的数字。<collation name="latin1_test_ci"> <map> 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49 44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49 44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF </map> </collation>
-
重新启动服务器,并使用此语句验证排序规则是否存在:
mysql> SHOW COLLATION WHERE Collation = 'latin1_test_ci'; +----------------+---------+------+---------+----------+---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +----------------+---------+------+---------+----------+---------+ | latin1_test_ci | latin1 | 1024 | | | 1 | +----------------+---------+------+---------+----------+---------+
12.14.4 向 Unicode 字符集添加 UCA 排序
原文:
dev.mysql.com/doc/refman/8.0/en/adding-collation-unicode-uca.html
12.14.4.1 使用 LDML 语法定义 UCA 排序
12.14.4.2 MySQL 支持的 LDML 语法
12.14.4.3 在 Index.xml 解析期间的诊断
本节描述了如何通过在 MySQL 的 Index.xml
文件中的 <charset>
字符集描述中编写 <collation>
元素来添加 Unicode 字符集的 UCA 排序。这里描述的过程不需要重新编译 MySQL。它使用了 Locale Data Markup Language (LDML) 规范的一个子集,可在 www.unicode.org/reports/tr35/
上找到。使用这种方法,您无需定义整个排序。相反,您从现有的“基本”排序开始,并描述新排序与基本排序的不同之处。以下表列出了可以定义 UCA 排序的 Unicode 字符集的基本排序。无法为 utf16le
创建用户定义的 UCA 排序;没有 utf16le_unicode_ci
排序可作为此类排序的基础。
表 12.4 可用于用户定义 UCA 排序的 MySQL 字符集
字符集 | 基本排序 |
---|---|
utf8mb4 |
utf8mb4_unicode_ci |
ucs2 |
ucs2_unicode_ci |
utf16 |
utf16_unicode_ci |
utf32 |
utf32_unicode_ci |
以下部分展示了如何添加使用 LDML 语法定义的排序,并提供了 MySQL 支持的 LDML 规则摘要。
原文:
dev.mysql.com/doc/refman/8.0/en/ldml-collation-example.html
12.14.4.1 使用 LDML 语法定义 UCA 整理
要为 Unicode 字符集添加 UCA 整理而无需重新编译 MySQL,请使用以下过程。如果您不熟悉用于描述整理排序特性的 LDML 规则,请参阅第 12.14.4.2 节,“MySQL 支持的 LDML 语法”。
该示例向utf8mb4
字符集添加了一个名为utf8mb4_phone_ci
的整理。该整理设计用于涉及用户发布其姓名和电话号码的 Web 应用程序的场景。电话号码可以以非常不同的格式给出:
+7-12345-67
+7-12-345-67
+7 12 345 67
+7 (12) 345 67
+71234567
处理这些类型值时引发的问题是,不同的允许格式使得搜索特定电话号码变得非常困难。解决方案是定义一个重新排序标点字符的新整理,使它们可忽略。
-
选择一个整理 ID,如第 12.14.2 节,“选择整理 ID”所示。以下步骤使用 ID 为 1029。
-
修改
Index.xml
配置文件。该文件位于由character_sets_dir
系统变量命名的目录中。您可以按照以下方式检查变量值,尽管路径名可能在您的系统上有所不同:mysql> SHOW VARIABLES LIKE 'character_sets_dir'; +--------------------+-----------------------------------------+ | Variable_name | Value | +--------------------+-----------------------------------------+ | character_sets_dir | /user/local/mysql/share/mysql/charsets/ | +--------------------+-----------------------------------------+
-
为整理选择一个名称,并在
Index.xml
文件中列出它。此外,您需要提供整理排序规则。找到正在添加整理的字符集的<charset>
元素,并添加一个指示整理名称和 ID 的<collation>
元素,以将名称与 ID 关联起来。在<collation>
元素内,提供包含排序规则的<rules>
元素:<charset name="utf8mb4"> ... <collation name="utf8mb4_phone_ci" id="1029"> <rules> <reset>\u0000</reset> <i>\u0020</i> <!-- space --> <i>\u0028</i> <!-- left parenthesis --> <i>\u0029</i> <!-- right parenthesis --> <i>\u002B</i> <!-- plus --> <i>\u002D</i> <!-- hyphen --> </rules> </collation> ... </charset>
-
如果您希望为其他 Unicode 字符集添加类似的整理,添加其他
<collation>
元素。例如,要定义ucs2_phone_ci
,请向<charset name="ucs2">
元素添加一个<collation>
元素。请记住,每个整理必须有其自己的唯一 ID。 -
重新启动服务器并使用此语句验证整理是否存在:
mysql> SHOW COLLATION WHERE Collation = 'utf8mb4_phone_ci'; +------------------+---------+------+---------+----------+---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +------------------+---------+------+---------+----------+---------+ | utf8mb4_phone_ci | utf8mb4 | 1029 | | | 8 | +------------------+---------+------+---------+----------+---------+
现在测试整理,确保它具有所需的属性。
创建一个包含一些使用新整理的示例电话号码的表:
mysql> CREATE TABLE phonebook (
name VARCHAR(64),
phone VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_phone_ci
);
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO phonebook VALUES ('Svoj','+7 912 800 80 02');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO phonebook VALUES ('Hf','+7 (912) 800 80 04');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO phonebook VALUES ('Bar','+7-912-800-80-01');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO phonebook VALUES ('Ramil','(7912) 800 80 03');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO phonebook VALUES ('Sanja','+380 (912) 8008005');
Query OK, 1 row affected (0.00 sec)
运行一些查询,查看忽略的标点字符是否实际上被忽略以进行比较和排序:
mysql> SELECT * FROM phonebook ORDER BY phone;
+-------+--------------------+
| name | phone |
+-------+--------------------+
| Sanja | +380 (912) 8008005 |
| Bar | +7-912-800-80-01 |
| Svoj | +7 912 800 80 02 |
| Ramil | (7912) 800 80 03 |
| Hf | +7 (912) 800 80 04 |
+-------+--------------------+
5 rows in set (0.00 sec)
mysql> SELECT * FROM phonebook WHERE phone='+7(912)800-80-01';
+------+------------------+
| name | phone |
+------+------------------+
| Bar | +7-912-800-80-01 |
+------+------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM phonebook WHERE phone='79128008001';
+------+------------------+
| name | phone |
+------+------------------+
| Bar | +7-912-800-80-01 |
+------+------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM phonebook WHERE phone='7 9 1 2 8 0 0 8 0 0 1';
+------+------------------+
| name | phone |
+------+------------------+
| Bar | +7-912-800-80-01 |
+------+------------------+
1 row in set (0.00 sec)
12.14.4.2 MySQL 支持的 LDML 语法
本节描述了 MySQL 识别的 LDML 语法。这是 LDML 规范中描述的语法的子集,可在www.unicode.org/reports/tr35/
找到,应该查阅以获取更多信息。MySQL 识别了足够大的语法子集,因此在许多情况下,可以从 Unicode 通用区域数据存储库下载排序定义,并将相关部分(即在<rules>
和</rules>
标记之间的部分)粘贴到 MySQL 的Index.xml
文件中。这里描述的规则都受支持,只是字符排序仅在主要级别发生。指定在次要或更高排序级别上存在差异的规则被识别(因此可以包含在排序定义中),但在主要级别被视为相等。
当 MySQL 服务器在解析Index.xml
文件时发现问题时,会生成诊断信息。请参阅第 12.14.4.3 节,“解析 Index.xml 时的诊断”。
字符表示
在 LDML 规则中命名的字符可以直接写出,也可以用\u*
nnnn*
格式,其中nnnn
是十六进制 Unicode 代码点值。例如,A
和á
可以直接写出,也可以写为\u0041
和\u00E1
。在十六进制值中,字母A
到F
不区分大小写;\u00E1
和\u00e1
是等效的。对于 UCA 4.0.0 排序,只能对基本多文种平面中的字符使用十六进制表示法,而不能对超出0000
到FFFF
的 BMP 范围的字符使用。对于 UCA 5.2.0 排序,可以对任何字符使用十六进制表示法。
Index.xml
文件本身应使用 UTF-8 编码编写。
语法规则
LDML 具有重置规则和移位规则,用于指定字符排序。排序规则被给定为一组以建立锚点的重置规则开头的规则,然后是指示字符相对于锚点如何排序的移位规则。
-
<reset>
规则本身不指定任何排序。相反,它“重置”后续移位规则,使它们相对于给定字符进行排序。以下任一规则都会将后续移位规则重置为相对于字母'A'
进行排序:<reset>A</reset> <reset>\u0041</reset>
-
<p>
、<s>
和<t>
移位规则定义了一个字符与另一个字符的主要、次要和三级差异:-
使用主要差异来区分不同的字母。
-
使用次要差异来区分重音变体。
-
使用三级差异来区分大小写变体。
以下任一规则指定了字符
'G'
的主要移位规则:<p>G</p> <p>\u0047</p>
-
-
<i>
移位规则表示一个字符与另一个字符排序相同。以下规则使'b'
与'a'
排序相同:<reset>a</reset> <i>b</i>
-
缩写的移位语法使用一对标签指定多个移位规则。以下表格显示了缩写语法规则与等效的非缩写规则之间的对应关系。
表 12.5 缩写的移位语法
缩写语法 非缩写语法 <pc>xyz</pc>
<p>x</p><p>y</p><p>z</p>
<sc>xyz</sc>
<s>x</s><s>y</s><s>z</s>
<tc>xyz</tc>
<t>x</t><t>y</t><t>z</t>
<ic>xyz</ic>
<i>x</i><i>y</i><i>z</i>
-
扩展是一个重置规则,为多字符序列建立锚点。MySQL 支持 2 到 6 个字符长的扩展。以下规则将
'z'
放在主级别比三个字符序列'abc'
更大:<reset>abc</reset> <p>z</p>
-
缩写是将多字符序列排序的移位规则。MySQL 支持 2 到 6 个字符长的缩写。以下规则将三个字符序列
'xyz'
放在主级别比'a'
更大:<reset>a</reset> <p>xyz</p>
-
长扩展和长缩写可以一起使用。这些规则将三个字符序列
'xyz'
放在主级别比三个字符序列'abc'
更大:<reset>abc</reset> <p>xyz</p>
-
正常的扩展语法使用
<x>
加上<extend>
元素来指定一个扩展。以下规则将字符'k'
放在二级别比序列'ch'
更大。也就是说,'k'
的行为就像它扩展到'c'
后跟着'h'
的字符一样:<reset>c</reset> <x><s>k</s><extend>h</extend></x>
这种语法允许长序列。这些规则将序列
'ccs'
放在三级别比序列'cscs'
更大:<reset>cs</reset> <x><t>ccs</t><extend>cs</extend></x>
LDML 规范将正常扩展语法描述为“棘手”。详细信息请参阅该规范。
-
先前的上下文语法使用
<x>
加上<context>
元素来指定字符前的上下文影响其排序方式。以下规则将'-'
放在二级比'a'
更大,但仅当'-'
出现在'b'
之后时:<reset>a</reset> <x><context>b</context><s>-</s></x>
-
先前的上下文语法可以包括
<extend>
元素。这些规则将'def'
放在主级别比'aghi'
更大,但仅当'def'
出现在'abc'
之后时:<reset>a</reset> <x><context>abc</context><p>def</p><extend>ghi</extend></x>
-
重置规则允许
before
属性。通常,在重置规则之后的移位规则指示在重置字符之后排序的字符。在具有before
属性的重置规则之后的移位规则指示在重置字符之前排序的字符。以下规则将字符'b'
立即放在主级别的'a'
之前:<reset before="primary">a</reset> <p>b</p>
允许的
before
属性值通过名称或等效的数值指定排序级别:<reset before="primary"> <reset before="1"> <reset before="secondary"> <reset before="2"> <reset before="tertiary"> <reset before="3">
-
重置规则可以命名逻辑重置位置而不是文字字符:
<first_tertiary_ignorable/> <last_tertiary_ignorable/> <first_secondary_ignorable/> <last_secondary_ignorable/> <first_primary_ignorable/> <last_primary_ignorable/> <first_variable/> <last_variable/> <first_non_ignorable/> <last_non_ignorable/> <first_trailing/> <last_trailing/>
这些规则将
'z'
放在主级别比具有默认 Unicode 排序元素表(DUCET)条目且不是 CJK 的不可忽略字符更大:<reset><last_non_ignorable/></reset> <p>z</p>
逻辑位置在下表中显示了代码点。
表 12.6 逻辑重置位置代码点
逻辑位置 Unicode 4.0.0 代码点 Unicode 5.2.0 代码点 <first_non_ignorable/>
U+02D0 U+02D0 <last_non_ignorable/>
U+A48C U+1342E <first_primary_ignorable/>
U+0332 U+0332 <last_primary_ignorable/>
U+20EA U+101FD <first_secondary_ignorable/>
U+0000 U+0000 <last_secondary_ignorable/>
U+FE73 U+FE73 <first_tertiary_ignorable/>
U+0000 U+0000 <last_tertiary_ignorable/>
U+FE73 U+FE73 <first_trailing/>
U+0000 U+0000 <last_trailing/>
U+0000 U+0000 <first_variable/>
U+0009 U+0009 <last_variable/>
U+2183 U+1D371 逻辑位置 Unicode 4.0.0 代码点 Unicode 5.2.0 代码点 -
<collation>
元素允许shift-after-method
属性,该属性影响移位规则的字符权重计算。该属性有以下允许的值:-
simple
: 计算字符权重,就像没有before
属性的重置规则一样。如果未给出属性,则这是默认值。 -
expand
: 使用扩展来处理重置规则后的偏移。
假设
'0'
和'1'
的权重分别为0E29
和0E2A
,我们想在'0'
和'1'
之间放置所有基本拉丁字母:<reset>0</reset> <pc>abcdefghijklmnopqrstuvwxyz</pc>
对于简单的移位模式,权重计算如下:
'a' has weight 0E29+1 'b' has weight 0E29+2 'c' has weight 0E29+3 ...
然而,在
'0'
和'1'
之间没有足够的空位来放置 26 个字符。结果是数字和字母混合在一起。要解决这个问题,使用
shift-after-method="expand"
。然后权重计算如下:'a' has weight [0E29][233D+1] 'b' has weight [0E29][233D+2] 'c' has weight [0E29][233D+3] ...
233D
是字符0xA48C
的 UCA 4.0.0 权重,它是最后一个非可忽略字符(排序中最大的字符,不包括 CJK)。UCA 5.2.0 类似,但使用3ACA
,对于字符0x1342E
。 -
MySQL 特定的 LDML 扩展
LDML 规则的扩展允许<collation>
元素在<collation>
标签中包含一个可选的version
属性,以指示排序所基于的 UCA 版本。如果省略version
属性,则其默认值为4.0.0
。例如,此规范指示基于 UCA 5.2.0 的排序:
<collation id="*nnn*" name="utf8mb4_*xxx*_ci" version="5.2.0">
...
</collation>
标签:字符,中文,utf8mb4,MySQL8,字符集,ci,mysql,排序,十九
From: https://www.cnblogs.com/apachecn/p/18263563