MySQL 中的字符集和排序规则

来自Wikioe
跳到导航 跳到搜索


MySQL Server 支持多种字符集。


要显示可用的字符集,请使用“INFORMATION_SCHEMA”的“CHARACTER_SETS”表或“SHOW CHARACTER SET”语句。

  • 默认情况下,“SHOW CHARACTER SET”语句显示所有可用字符集。它带有一个可选的“LIKE”或“WHERE”子句,该子句指示要匹配的字符集名称:
    mysql> SHOW CHARACTER SET LIKE 'latin%';
    +---------+-----------------------------+-------------------+--------+
    | Charset | Description                 | Default collation | Maxlen |
    +---------+-----------------------------+-------------------+--------+
    | 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 |
    +---------+-----------------------------+-------------------+--------+
    


给定的字符集始终至少具有一个排序规则,大多数字符集具有多个排序规则。要列出字符集的显示归类,请使用“INFORMATION_SCHEMA”的“COLLATIONS”表或“SHOW COLLATION”语句。

  • 默认情况下,“SHOW COLLATION”语句显示所有可用的排序规则。它带有一个可选的“LIKE”或“WHERE”子句,该子句指示要显示的排序规则名称。
    mysql> SHOW COLLATION WHERE Charset = 'latin1';
    +-------------------+---------+----+---------+----------+---------+
    | Collation         | Charset | Id | Default | Compiled | Sortlen |
    +-------------------+---------+----+---------+----------+---------+
    | latin1_german1_ci | latin1  |  5 |         | Yes      |       1 |
    | latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       1 |
    | latin1_danish_ci  | latin1  | 15 |         | Yes      |       1 |
    | latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
    | latin1_bin        | latin1  | 47 |         | Yes      |       1 |
    | latin1_general_ci | latin1  | 48 |         | Yes      |       1 |
    | latin1_general_cs | latin1  | 49 |         | Yes      |       1 |
    | latin1_spanish_ci | latin1  | 94 |         | Yes      |       1 |
    +-------------------+---------+----+---------+----------+---------+
    


排序规则一般具有以下特征:

  • 两种不同的字符集不能具有相同的排序规则。
  • 每个字符集都有一个“默认排序规则”。
    例如,latin1 和 utf8 的默认排序规则分别为 latin1_swedish_ci 和 utf8_general_ci 。
    • “INFORMATION_SCHEMA”的“CHARACTER_SET”表和“SHOW CHARACTER SET”语句指示每个字符集的默认排序规则。
    • “INFORMATION_SCHEMA”的“COLLATIONS”表和“SHOW COLLATION”语句具有一列,该列指示每个排序规则是否为其字符集的默认字符集(如果是Yes,则为空)。
  • 排序规则名称以它们所关联的字符集的名称开头,通常后跟一个或多个后缀,以表示其他排序规则特征。

字符集库

字符集的库是字符集中的字符集合。

字符串表达式具有一个库属性,该属性可以具有两个值:

  1. ASCII:表达式只能包含 ASCII 字符;也就是说,Unicode 范围是U+0000到U+007F的字符。
  2. UNICODE:表达式可以包含 Unicode 范围U+0000到U+10FFFF的字符。这包括基本多语言平面(BMP)范围内的字符(U+0000至U+FFFF)和 BMP 范围外的辅助字符(U+10000至U+10FFFF)。
  • ASCII 范围是 UNICODE 范围的子集,因此具有 ASCII 库的字符串可以安全地转换,而不会丢失任何具有 UNICODE 库的字符串的信息集。也可以将其安全地转换为 ascii 字符集的超集的任何字符集。 (所有 MySQL 字符集都是ascii的超集,但swe7除外,后者将一些标点符号重用为瑞典的带重音符号的字符.)
  • 在大多数情况下,当排序规则强制性的规则不足以解决歧义性时,MySQL 否则会返回“非法的排序规则混合”错误,因此使用库可以在表达式中进行字符集转换。


以下讨论提供了表达式及其组成部分的示例,并描述了组成部分的使用如何更改字符串表达式求值:

  1. 字符串常量的库取决于字符串内容,并且可能与字符串字符集的库不同。考虑以下语句:
    SET NAMES utf8; SELECT 'abc';
    SELECT _utf8'def';
    SELECT N'MySQL';
    
    尽管在上述每种情况下,字符集均为utf8,但这些字符串实际上并不包含 ASCII 范围以外的任何字符,因此它们的字符集为 ASCII 而不是 UNICODE。
  2. 由于其字符集,具有 ascii 字符集的列具有ASCII指令库。在下表中,c1具有ASCII曲目:
    CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET ascii);
    
    在没有库的情况下发生错误的情况下,库可以如何确定结果:
    CREATE TABLE t1 (
      c1 CHAR(1) CHARACTER SET latin1,
      c2 CHAR(1) CHARACTER SET ascii
    );
    INSERT INTO t1 VALUES ('a','b');
    SELECT CONCAT(c1,c2) FROM t1;
    
    没有曲目,则会发生此错误:
    ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT)
    and (ascii_general_ci,IMPLICIT) for operation 'concat'
    
    使用库,可以发生子集到超集(ascii到latin1)的转换,并返回结果:
    +---------------+
    | CONCAT(c1,c2) |
    +---------------+
    | ab            |
    +---------------+
    
  3. 具有一个字符串参数的函数将继承其参数库。 UPPER(_utf8'abc') 的结果具有ASCII指令库,因为其自变量具有ASCII指令库。 (尽管使用_utf8引入程序,但字符串'abc'不包含 ASCII 范围之外的字符.)
  4. 对于返回字符串但没有字符串参数并使用“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                 |
    +-------------------------+
    
  5. 具有两个或多个字符串参数的函数使用“最宽”参数表作为结果表,其中 UNICOD E比 ASCII 宽。考虑以下“CONCAT()”调用:
    CONCAT(_ucs2 X'0041', _ucs2 X'0042')
    CONCAT(_ucs2 X'0041', _ucs2 X'00C2')
    
    对于第一个调用,指令集为ASCII,因为两个参数都在 ASCII 范围内。对于第二个调用,由于第二个参数在 ASCII 范围之外,因此指令集为UNICODE。
  6. 函数返回值的库是根据仅影响结果的字符集和排序规则的那些参数的库确定的。
    IF(column1 < column2, 'smaller', 'greater')
    
    结果库为ASCII,因为两个字符串参数(第二个参数和第三个参数)都具有ASCII个库。即使 table 达式使用字符串值,第一个参数对于结果库也不重要。

UTF-8(用于元数据)

元数据是“关于数据的数据”。描述数据库的任何内容(而不是数据库的内容)都是元数据。

  1. 因此,“列名”,“数据库名”,“用户名”,“版本名”以及“SHOW”的大多数字符串结果都是元数据。
  2. “INFORMATION_SCHEMA”中表的内容也是如此,因为按定义这些表包含有关数据库对象的信息。


元数据的表示形式必须满足以下要求:

  1. 所有元数据必须使用相同的字符集。否则,“INFORMATION_SCHEMA中”的表的“SHOW”语句或“SELECT”语句都将无法正常工作,因为这些操作结果的同一列中的不同行将使用不同的字符集。
  2. 元数据必须包含所有语言的所有字符。否则,用户将无法使用自己的语言命名列和表。

为了满足这两个要求,MySQL 将元数据存储在 Unicode 字符集(即 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 | utf8  |
+----------------------+-------+


使用 Unicode 存储元数据并不意味着服务器默认以“character_set_system”所设置的字符集来返回列标题和“DESCRIBE”函数:

当使用“SELECT column1 FROM t”时,column1的名称会以系统变量“character_set_results”所确定的字符集(默认值为utf8)从服务器返回到 Client 端。
  • 如果希望服务器将元数据结果传递回不同的字符集:
    1. 请使用“SET NAMES”语句强制服务器执行字符集转换。
    2. 或者,Client 端程序可以在从服务器接收到结果之后执行转换。【Client 端执行转换效率更高,但是此选项并非始终对所有 Client 端都可用】
  • 如果“character_set_results”设置为 NULL,则不执行任何转换,并且服务器使用其原始字符集(由“character_set_system”指示的字符集)返回元数据。
  • (从服务器返回到 Client 端的错误消息将与元数据一样自动转换为 Client 端字符集)
  • 如果您正在使用诸如“USER()”等函数在单个语句中进行比较或赋值,请不要担心。MySQL 为您执行一些自动转换
    SELECT * FROM t1 WHERE USER() = latin1_column;
    
    之所以可行,是因为在比较之前 latin1_column 的内容会自动转换为 UTF-8.
    INSERT INTO t1 (latin1_column) SELECT USER();
    
    之所以有效,是因为分配之前“USER()”的内容会自动转换为 latin1。