MySQL 字符集:指定字符集和排序规则
关于
字符集和排序规则有四个级别的默认设置:服务器,数据库,表 和 列。
“CHARACTER SET”用于指定字符集的子句中。【 “CHARSET”可以用作“CHARACTER SET”的同义词】
字符集问题不仅影响数据存储,还影响 Client 端程序与 MySQL 服务器之间的通信。如果希望 Client 端程序使用与默认字符集不同的字符集与服务器通信,则需要指出哪个字符集。
- 例如,要使用 utf8 Unicode 字符集,请在连接到服务器后发出以下语句:
SET NAMES 'utf8';
排序规则命名约定
MySQL 排序规则名称遵循以下约定:
- 排序规则名称以与其关联的字符集的名称开头,通常后跟一个或多个后缀,以指示其他排序规则特征。例如,“utf8_general_ci”和“latin1_swedish_ci”分别是“utf8”和“latin1”字符集的排序规则。
- binary字符集具有单个排序规则,也称为binary,没有后缀。
- 特定于语言的排序规则包括语言名称。例如,“utf8”字符集的“utf8_turkish_ci”和“utf8_hungarian_ci”使用土耳其语和匈牙利语规则分别对字符进行排序。
- 排序规则后缀指示排序规则是区分大小写,区分重音还是假名敏感(或其某种组合)还是二进制。下表显示了用于指示这些特性的后缀。
排序规则后缀的含义:
Suffix | Meaning |
---|---|
_ai | 重音:不敏感(Accent-sensitive) |
_as | 重音:敏感(Accent-sensitive) |
_ci | 大小写:不敏感(Case-insensitive) |
_cs | 大小写:敏感(Case-sensitive) |
_bin | 二进制(Binary) |
- 对于未指定重音符号敏感性的非二进制排序规则名称,它由区分大小写确定。如果排序规则名称不包含“_ai”或“_as”,则名称中的“_ci”表示“_ai”,名称中的“_cs”表示“_as”。
- 例如,“latin1_general_ci”显式不区分大小写,并且隐含不区分重音,而“latin1_general_cs”显式区分大小写,并且隐含区分重音。
- 对于二进制字符集的二进制排序规则,比较基于数字字节值。对于非二进制字符集的“_bin”排序规则,比较基于数字字符代码值,该值不同于多字节字符的字节值。
- Unicode 字符集的排序规则名称可以包括版本号,以指示排序规则所基于的 Unicode 排序规则算法(UCA)的版本。名称中没有版本号的基于 UCA 的归类使用版本 4.0.0 UCA 配重键。
- 例如:
- utf8_unicode_520_ci:基于 UCA 5.2.0 配重键(http://www.unicode.org/Public/UCA/5.2.0/allkeys.txt)。
- utf8_unicode_ci(未命名版本):基于 UCA 4.0.0 重量键(http://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 之前创建的表(错误#27877)。
服务器字符集和排序规则
MySQL Server 具有服务器字符集和服务器排序规则。默认情况下,它们是“latin1”和“latin1_swedish_ci”,但是可以在服务器启动时在命令行或配置文件中显式设置它们,并在运行时进行更改。
最初,服务器字符集和排序规则取决于启动 mysqld 时使用的选项:可以使用“--character-set-server”作为字符集,同时,可以使用“--collation-server”作为排序规则添加:
- 如果未指定字符集,则与“--character-set-server=latin1”相同。
- 如果仅指定字符集而不指定排序规则,则使用的默认排序规则。
因此,以下三个命令都具有相同的效果:
mysqld
mysqld --character-set-server=latin1
mysqld --character-set-server=latin1 --collation-server=latin1_swedish_ci
更改设置的一种方法是重新编译。要从源代码构建时更改默认服务器字符集和排序规则,请对“CMake”使用“DEFAULT_CHARSET”和“DEFAULT_COLLATION”选项。例如:
cmake . -DDEFAULT_CHARSET=latin1
Or:
cmake . -DDEFAULT_CHARSET=latin1 -DDEFAULT_COLLATION=latin1_german1_ci
- mysqld和 CMake 都验证字符集/排序规则组合是否有效。如果不是,则每个程序都会显示一条错误消息并终止。
- 如果未在“CREATE DATABASE”语句中指定数据库字符集和排序规则,则将服务器字符集和排序规则用作默认值。
- 可以从“character_set_server”和“collation_server”系统变量的值确定当前服务器的字符集和排序规则。这些变量可以在运行时更改。
数据库字符集和排序规则
每个数据库都有一个数据库字符集和一个数据库排序规则。“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。
- 可以使用关键字“SCHEMA”代替“DATABASE”。
- 所有数据库选项都存储在名为“db.opt”的文本文件中,该文件可在数据库目录中找到。
- “CHARACTER SET”和“COLLATE”子句可以在同一 MySQL 服务器上创建具有不同字符集和排序规则的数据库:
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”子句。
- 对于存储的例程(过程和函数),将在例程创建时生效的数据库字符集和排序规则用作声明不包含“CHARACTER SET”或“COLLATE”属性的字符数据参数的字符集和排序规则。要覆盖它,请显式提供“CHARACTER SET”或“COLLATE”。
表字符集和排序规则
每个表都有一个表字符集和一个表排序规则。“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 中没有这样的东西】
列字符集和排序规则
每个“字符”列(即“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 utf8 COLLATE utf8_unicode_ci ) CHARACTER SET latin1 COLLATE latin1_bin;
- 如果指定的“CHARACTER SET charset_name”不带“COLLATE”,则使用字符集“charset_name”及其默认排序规则。
CREATE TABLE t1 ( col1 CHAR(10) CHARACTER SET utf8 ) CHARACTER SET latin1 COLLATE latin1_bin;
- 【要查看每个字符集的默认排序规则,请使用“SHOW CHARACTER SET”语句或查询“INFORMATION_SCHEMA”的“CHARACTER_SETS”表。】
- 如果指定的“COLLATE collation_name”不带“CHARACTER SET”,则使用与“collation_name”关联的字符集和排序规则“collation_name”。
CREATE TABLE t1 ( col1 CHAR(10) COLLATE utf8_polish_ci ) CHARACTER SET latin1 COLLATE latin1_bin;
- 否则(既未指定“CHARACTER SET”也未指定“COLLATE”),则使用数据库字符集和排序规则。
CREATE TABLE t1 ( col1 CHAR(10) ) CHARACTER SET latin1 COLLATE latin1_bin;
- “CHARACTER SET”和“COLLATE”子句是标准 SQL。
- 如果使用“ALTER TABLE”将列从一个字符集转换为另一个字符集,则 MySQL 会尝试映射数据值,但是如果字符集不兼容,则可能会丢失数据。
字符串常量字符集和排序规则
每个字符串常量都有一个字符集和一个排序规则。对于简单语句“SELECT 'string'”,该字符串具有由“character_set_connection”【区别于“character_set_server”和“character_set_database”】和“collation_connection”【区别于“collation_server”和“collation_database”】系统变量定义的连接默认字符集和排序规则。
字符串常量可能具有可选的字符集导引器和“COLLATE”子句,以将其指定为使用特定字符集和排序规则的字符串:
[_charset_name]'string' [COLLATE collation_name]
“_charset_name”表达式正式名称为“导引器”(introducer) 。它告诉解析器,“后面的字符串使用字符集‘charset_name’”引入程序不会像“CONVERT()”那样将字符串更改为引入程序字符集。尽管可能会发生填充,但它不会更改字符串值。
示例:
SELECT 'abc';
SELECT _latin1'abc';
SELECT _binary'abc';
SELECT _utf8'abc' COLLATE utf8_danish_ci;
MySQL 通过以下方式确定字符集和字符串常量的排序规则:
- 如果同时指定了“_charset_name”和“COLLATE collation_name”,则使用字符集“charset_name”和排序规则“collation_name”。(“collation_name”必须是“charset_name”的允许排序规则)
- 如果指定“_charset_name”但未指定“COLLATE”,则使用字符集“charset_name”及其默认排序规则。
- 如果未指定“_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;
- 具有utf8字符集及其默认排序规则(即utf8_general_ci)的非二进制字符串:
SELECT _utf8'Müller';
- 具有binary字符集和默认排序规则(即binary)的二进制字符串:
SELECT _binary'Müller';
- 具有连接默认字符集和utf8_general_ci排序规则的非二进制字符串(如果连接字符集不是utf8,则失败):
SELECT 'Müller' COLLATE utf8_general_ci;
- 具有连接默认字符集和排序规则的字符串:
SELECT 'Müller';
“导引器”仅表示其后字符串的字符集,而不更改解析器在字符串内执行转义处理的方式。解析器始终根据“character_set_connection”给出的字符集来解释转义。
- 以下示例显示,即使存在引入程序,也使用“character_set_connection”进行转义处理。这些示例使用“SET NAMES”(将更改“character_set_connection”)并使用“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”引入器不会影响转义处理。
国家字符集【???】
标准 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';
字符集导引器【???】
字符串常量,十六进制常量 或 位值常量 可以具有可选的字符集导引器和“COLLATE”子句,以将其指定为使用特定字符集和排序规则的字符串:
[_charset_name] literal [COLLATE collation_name]
“_charset_name”表达式正式名称为“导引器”(introducer) 。它告诉解析器,“后面的字符串使用字符集‘charset_name’”引入程序不会像“CONVERT()”那样将字符串更改为引入程序字符集。尽管可能会发生填充,但它不会更改字符串值:
- 对于字符串常量,导引器和字符串之间的空格是允许的,但是可选的。
- 对于字符集常量,导引器指表示其后字符串的字符集,但不更改解析器在字符串内执行转义处理的方式。解析器始终根据“character_set_connection”给出的字符集来解释转义。
示例:
SELECT 'abc';
SELECT _latin1'abc';
SELECT _binary'abc';
SELECT _utf8'abc' COLLATE utf8_danish_ci;
SELECT _latin1 X'4D7953514C';
SELECT _utf8 0x4D7953514C COLLATE utf8_danish_ci;
SELECT _latin1 b'1000001';
SELECT _utf8 0b1000001 COLLATE utf8_danish_ci;
可以使用“_binary”导引器将字符串常量指定为二进制字符串。十六进制常量和位值常量默认情况下是二进制字符串,因此_binary是允许的,但不必要。
MySQL 通过以下方式确定字符串常量,十六进制常量 或 位值常量 的字符集和排序规则:
- 如果同时指定了“_charset_name”和“COLLATE collation_name”,则使用字符集“charset_name”和排序规则“collation_name”。(“collation_name”必须是“charset_name”的允许排序规则)
- 如果指定“_charset_name”但未指定“COLLATE”,则使用字符集“charset_name”及其默认排序规则。
- 如果未指定“_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;
- 具有 utf8 字符集及其默认排序规则(即 utf8_general_ci)的非二进制字符串:
SELECT _utf8'Müller'; SELECT _utf8 X'0A0D'; SELECT _utf8 b'0110';
- 具有 binary 字符集及其默认排序规则(即 binary)的二进制字符串:
SELECT _binary'Müller'; SELECT X'0A0D'; SELECT b'0110';
- 十六进制常量和位值常量不需要引入符,因为默认情况下它们是二进制字符串。
- 具有连接默认字符集和 utf8_general_ci 排序规则的非二进制字符串(如果连接字符集不是 utf8,则失败):
SELECT 'Müller' COLLATE utf8_general_ci;
- 此构造(仅COLLATE)不适用于十六进制常量或位常量,因为无论连接字符集如何,其字符集均为 binary,并且 binary 与 utf8_general_ci 排序规则不兼容。在没有简介的情况下,唯一允许的“COLLATE”子句是“COLLATE binary”。
- 具有连接默认字符集和排序规则的字符串:
SELECT 'Müller';
与其他 DBMS 的兼容性
为了实现 MaxDB 兼容性,这两个语句是相同的:
CREATE TABLE t1 (f1 CHAR(N) UNICODE);
CREATE TABLE t1 (f1 CHAR(N) CHARACTER SET ucs2);