📓 Archive

03_CHARACTER_AND_COLLATION

FGJ: Create:2023/11/28 Update: [2024-12-16]

字符集和比较规则简介 #

字符集简介 #

我们知道在计算机中只能存储二进制数据,那该怎么存储字符串呢?当然是建立字符与二进制数据的映射关系了,建立这个关系最起码要搞清楚两件事儿:

  1. 你要把哪些字符映射成二进制数据?(也就是界定清楚字符范围)
  2. 怎么映射? 将一个字符映射成二进制数据的过程叫编码,将一个二进制数据映射到一个字符的过程叫解码

人们抽象出一个字符集的概念来描述某个字符范围的编码规则。比方说我们来自定义一个名称为 xiaohaizi的字符集,它包括的字符范围和编码规则如下:

  • 包含的字符’a’、‘b’、‘A’、‘B’

  • 编码的规则如下:

    采用一个字节编码一个字符的形式,字符和字节的映射关系如下: ‘a’ -> 00000001 (十六进制:0x01) ‘b’ -> 00000010 (十六进制:0x02) ‘A’ -> 00000011 (十六进制:0x03) ‘B’ -> 00000100 (十六进制:0x04)

有了xiaohaizi 字符集,我们就可以用二进制形式表示一些字符串了,下边是一些字符串用 xiaohaizi字符编码后的二进制表示:

'bA' -> 0000001000000011 (十六进制:0x0203)
'baB' -> 000000100000000100000100 (十六进制:0x020104)
'cd' -> 无法表示,字符集xiaohaizi不包含字符'c'和'd'

比较规则简介 #

在我们确定了 xiaohaizi 字符集表示字符的范围以及编码规则后,怎么比较两个字符的大小呢?最容易想到的就是直接比较这两个字符对应的二进制编码的大小,比方说字符 ‘a’ 的编码为 0x01 ,字符 ‘b’ 的编码为 0x02 ,所以 ‘a’ 小于 ‘b’ ,这种简单的比较规则也可以被称为二进制比较规则,英文名为 binary collation 。二进制比较规则是简单,但有时候并不符合现实需求,比如在很多场合对于英文字符我们都是不区分大小写的,也就是说 ‘a’ 和 ‘A’ 是相等的,在这种场合下就不能简单粗暴的使用二进制比较规则了,这时候我们可以这样指定比较规则:

  1. 将两个大小写不同的字符全都转为大写或者小写。
  2. 再比较这两个字符对应的二进制数据。

这是一种稍微复杂一点点的比较规则,但是实际生活中的字符不止英文字符一种,比如我们的汉字有几万之多,对于某一种字符集来说,比较两个字符大小的规则可以制定出很多种,也就是说同一种字符集可以有多种比较规则,我们稍后就要介绍各种现实生活中用的字符集以及它们的一些比较规则。

一些重要的字符集 #

不幸的是,这个世界太大了,不同的人制定出了好多种 字符集 ,它们表示的字符范围和用到的编码规则可能都不一样。我们看一下一些常用字符集的情况:

* ASCII 字符集 #

共收录128个字符,包括空格、标点符号、数字、大小写字母和一些不可见字符。由于总共才128个字符,所以可以使用1个字节来进行编码,我们看一些字符的编码方式:

'L' -> 01001100(十六进制:0x4C,十进制:76)
'M' -> 01001101(十六进制:0x4D,十进制:77)

* ISO 8859-1 字符集 #

共收录256个字符,是在 ASCII 字符集的基础上又扩充了128个西欧常用字符(包括德法两国的字母),也可以使用1个字节来进行编码。这个字符集也有一个别名 latin1 。

* GB2312 字符集 #

收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。其中收录汉字6763个,其他文字符号682个。同时这种字符集又兼容 ASCII 字符集,所以在编码方式显得有些奇怪:

  • 如果该字符在 ASCII 字符集中,则采用1字节编码。
  • 否则采用2字节编码。

这种表示一个字符需要的字节数可能不同的编码方式称为 变长编码方式 。比方说字符串 ‘爱u’ ,其中 ‘爱’ 需要用2个字节进行编码,编码后的十六进制表示为 0xCED2 , ‘u’ 需要用1个字节进行编码,编码后的十六进制表示为 0x75 ,所以拼合起来就是 0xCED275 。

小贴士:我们怎么区分某个字节代表一个单独的字符还是代表某个字符的一部分呢?别忘了ASCII字符集只收录128个字符,使用0~127就可以表示全部字符,所以如果某个字节是在0~127之内的,就意味着一个字节代表一个单独的字符,否则就是两个字节代表一个单独的字符。

* GBK 字符集 #

GBK 字符集只是在收录字符范围上对 GB2312 字符集作了扩充,编码方式上兼容 GB2312 。

* utf8 字符集 #

收录地球上能想到的所有字符,而且还在不断扩充。这种字符集兼容 ASCII 字符集,采用变长编码方式,编码一个字符需要使用1~4个字节,比方说这样: ‘L’ -> 01001100(十六进制:0x4C) ‘啊’ -> 111001011001010110001010(十六进制:0xE5958A)

小贴士:其实准确的说,utf8只是Unicode字符集的一种编码方案,Unicode字符集可以采用utf8、utf16、utf32这几种编码方案,utf8使用1~4个字节编码一个字符,utf16使用2个或4个字节编码一个字符,utf32使用4个字节编码一个字符。更详细的Unicode和其编码方案的知识不是本书的重点,大家上网查查哈~

MySQL中并不区分字符集和编码方案的概念,所以后边唠叨的时候把utf8、utf16、utf32都当作一种字符集对待。

对于同一个字符,不同字符集也可能有不同的编码方式。比如对于汉字 ‘我’ 来说, ASCII 字符集中根本没有收录这个字符, utf8 和 gb2312 字符集对汉字 我 的编码方式如下:

utf8编码:111001101000100010010001 (3个字节,十六进制表示是:0xE68891) gb2312编码:1100111011010010 (2个字节,十六进制表示是:0xCED2)

MySQL中支持的字符集和比较规则 #

Mysql中utf8和utf8mb4 #

我们上边说 utf8 字符集表示一个字符需要使用1~4个字节,但是我们常用的一些字符使用1~3个字节就可以表示了。而在 MySQL 中字符集表示一个字符所用最大字节长度在某些方面会影响系统的存储和性能,所以设计MySQL 的大叔偷偷的定义了两个概念:

  • utf8mb3 :阉割过的 utf8 字符集,只使用1~3个字节表示字符。
  • utf8mb4 :正宗的 utf8 字符集,使用1~4个字节表示字符。

有一点需要大家十分的注意,在 MySQL 中 utf8 是 utf8mb3 的别名,所以之后在 MySQL 中提到 utf8 就意味着使用1~3个字节来表示一个字符,如果大家有使用4字节编码一个字符的情况,比如存储一些emoji表情啥的,那请使用 utf8mb4 。

字符集的查看 #

# MySQL 支持好多好多种字符集,查看当前 MySQL 中支持的字符集可以用下边这个语句:
SHOW CHARACTER SET [like_or_where];
like_or_where: {
    LIKE 'pattern'
  | WHERE expr
}
# 其中 CHARACTER SET 和 CHARSET 是同义词,用任意一个都可以。其中的 Default collation 列表示这种字符集中一种默认的 比较规则 。大家注意返回结果中的最后一列 Maxlen ,它代表该种字符集表示一个字符最多需要几个字节。
  1. show charset;

  2. show charset like '%utf%';

  3. show charset where charset = 'utf8mb4';

比较规则查看 #

# 查看 MySQL 中支持的比较规则的命令如下:
SHOW COLLATION [like_or_where]
like_or_where: {
    LIKE 'pattern'
  | WHERE expr
}

这些比较规则的命名还挺有规律的,具体规律如下:

  • 比较规则名称以与其关联的字符集的名称开头。如上图的查询结果的比较规则名称都是以 utf8 开头的。
  • 后边紧跟着该比较规则主要作用于哪种语言,比如 utf8_polish_ci 表示以波兰语的规则比较,utf8_spanish_ci 是以西班牙语的规则比较, utf8_general_ci 是一种通用的比较规则。
  • 名称后缀意味着该比较规则是否区分语言中的重音、大小写啥的,具体可以用的值如下:
    后缀英文释义描述
    _aiaccent insensitive不区分重音
    _asaccent sensitive区分重音
    _cicase insensitive不区分大小写
    _cscase sensitive区分大小写
    _binbinary以二进制方式比较
  1. show collation where charset = 'utf8mb4';

  2. show collation where charset = 'utf8mb4';

字符集和比较规则的应用 #

各级别的字符集和比较规则 #

MySQL 有4个级别的字符集和比较规则,分别是:服务器级别,数据库级别,表级别,列级别.

1. 服务器级别 #

MySQL 提供了两个系统变量来表示服务器级别的字符集和比较规则:

  • show variables like 'character_set_server';

  • show variables like 'collation_server';

可以看到在我的计算机中服务器级别默认的字符集是 utf8mb4 ,默认的比较规则是 utf8mb4_unicode_ci 。我们可以在启动服务器程序时通过启动选项或者在服务器程序运行过程中使用 SET 语句修改这两个变量的值。比如我们可以在配置文件中如下写:当服务器启动的时候读取这个配置文件后这两个系统变量的值便修改了。

[server]
character_set_server=gbk
collation_server=gbk_chinese_ci

2. 数据库级别 #

我们在创建和修改数据库的时候可以指定该数据库的字符集和比较规则,具体语法如下:

CREATE DATABASE 数据库名
    [[DEFAULT] CHARACTER SET 字符集名称]
    [[DEFAULT] COLLATE 比较规则名称];
ALTER DATABASE 数据库名
    [[DEFAULT] CHARACTER SET 字符集名称]
    [[DEFAULT] COLLATE 比较规则名称];

# 其中的 DEFAULT 可以省略,并不影响语句的语义。比方说我们新创建一个名叫 charset_demo_db 的数据库,在创建的时候指定它使用的字符集为 gb2312 ,比较规则为 gb2312_chinese_ci :
mysql> CREATE DATABASE charset_demo_db
    -> CHARACTER SET gb2312
    -> COLLATE gb2312_chinese_ci;
Query OK, 1 row affected (0.01 sec)

如果想查看当前数据库使用的字符集和比较规则,可以查看下面两个系统变量的值(前提是使用 USE 语句选择当前默认数据库,如果没有默认数据库,则变量与相应的服务器级系统变量具有相同的值):

  • select database();

  • show variables like 'character_set_database';

  • show variables like 'collation_database';

  • show create database myemployees\G

character_set_database 和 collation_database 这两个系统变量是只读的,我们不能通过修改这两个变量的值而改变当前数据库的字符集和比较规则。

3. 表级别 #

我们也可以在创建和修改表的时候指定表的字符集和比较规则,语法如下:

CREATE TABLE 表名 (列的信息)
    [[DEFAULT] CHARACTER SET 字符集名称]
    [COLLATE 比较规则名称]]
ALTER TABLE 表名
    [[DEFAULT] CHARACTER SET 字符集名称]
    [COLLATE 比较规则名称]

比方说我们在刚刚创建的 charset_demo_db 数据库中创建一个名为 t 的表,并指定这个表的字符集和比较规则:
mysql> CREATE TABLE t(
    -> col VARCHAR(10)
    -> ) CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 0 rows affected (0.03 sec)

如果创建和修改表的语句中没有指明字符集和比较规则,将使用该表所在数据库的字符集和比较规则作为该表的字符集和比较规则。
  • show create table jobs\G

  • select table_schema, table_collation from information_schema.tables where table_name = 'jobs'\G

4. 列级别 #

需要注意的是,对于存储字符串的列,同一个表中的不同的列也可以有不同的字符集和比较规则。我们在创建和修改列定义的时候可以指定该列的字符集和比较规则,语法如下:

CREATE TABLE 表名(
 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],
 其他列...
);
ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];
# 比如我们修改一下表 t 中列 col 的字符集和比较规则可以这么写:
mysql> ALTER TABLE t MODIFY col VARCHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0

对于某个列来说,如果在创建和修改的语句中没有指明字符集和比较规则,将使用该列所在表的字符集和比较规则作为该列的字符集和比较规则。比方说表 t 的字符集是 utf8 ,比较规则是 utf8_general_ci ,修改列 col 的语句是这么写的:
ALTER TABLE t MODIFY col VARCHAR(10);
那列 col 的字符集和编码将使用表 t 的字符集和比较规则,也就是 utf8 和 utf8_general_ci 。
  • SHOW FULL COLUMNS FROM t;

  • SELECT column_name, character_set_name, collation_name FROM information_schema.columns WHERE table_schema = 'myemployees' AND table_name = 't';

    下图是后面补上去的,所以和第一种方式比较内容有差别

小贴士:在转换列的字符集时需要注意,如果转换前列中存储的数据不能用转换后的字符集进行表示会发生错误。比方说原先列使用的字符集是utf8,列中存储了一些汉字,现在把列的字符集转换为ascii的话就会出错,因为ascii字符集并不能表示汉字字符。

仅修改字符集或仅修改比较规则 #

由于字符集和比较规则是互相有联系的,如果我们只修改了字符集,比较规则也会跟着变化,如果只修改了比较规则,字符集也会跟着变化,具体规则如下:

  • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。
  • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。

不论哪个级别的字符集和比较规则,这两条规则都适用,我们以服务器级别的字符集和比较规则为例来看一下详细过程:

  • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。

    我们只修改了 character_set_server 的值为 utf8mb4 , collation_server 的值自动变为了utf8mb4_general_ci 。

  • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。

    我们只修改了 collation_server 的值为 gb2312_chinese_ci , character_set_server 的值自动变为了 gb2312 。

各级别字符集和比较规则小结 #

我们介绍的这4个级别字符集和比较规则的联系如下:

  • 如果创建或修改列时没有显式的指定字符集和比较规则,则该列默认用表的字符集和比较规则
  • 如果创建或修改表时没有显式的指定字符集和比较规则,则该表默认用数据库的字符集和比较规则
  • 如果创建或修改数据库时没有显式的指定字符集和比较规则,则该数据库默认用服务器的字符集和比较规则

知道了这些规则之后,对于给定的表,我们应该知道它的各个列的字符集和比较规则是什么,从而根据这个列的类型来确定存储数据时每个列的实际数据占用的存储空间大小了。比方说我们向表 t 中插入一条记录:INSERT INTO t(col) VALUES('我我');首先列 col 使用的字符集是 gbk ,一个字符 ‘我’ 在 gbk 中的编码为 0xCED2 ,占用两个字节,两个字符的实际 数据就占用4个字节。如果把该列的字符集修改为 utf8 的话,这两个字符就实际占用6个字节啦~

客户端和服务器通信中的字符集 #

编码和解码使用的字符集不一致的后果 #

说到底,字符串在计算机上的体现就是一个字节串,如果你使用不同字符集去解码这个字节串,最后得到的结果可能让你挠头。 我们知道字符 ‘我’ 在 utf8 字符集编码下的字节串长这样: 0xE68891 ,如果一个程序把这个字节串发送到另一个程序里,另一个程序用不同的字符集去解码这个字节串,假设使用的是gbk 字符集来解释这串字节,解码过程就是这样的:

  1. 首先看第一个字节 0xE6 ,它的值大于 0x7F (十进制:127),说明是两字节编码,继续读一字节后是0xE688 ,然后从 gbk 编码表中查找字节为 0xE688 对应的字符,发现是字符 ‘鎴’
  2. 继续读一个字节 0x91 ,它的值也大于 0x7F ,再往后读一个字节发现木有了,所以这是半个字符。
  3. 所以 0xE68891 被 gbk 字符集解释成一个字符 ‘鎴’ 和半个字符。

假设用 iso-8859-1 ,也就是 latin1 字符集去解释这串字节,解码过程如下: 1. 先读第一个字节 0xE6 ,它对应的 latin1 字符为 æ 。 2. 再读第二个字节 0x88 ,它对应的 latin1 字符为 ˆ 。 3. 再读第二个字节 0x91 ,它对应的 latin1 字符为 ‘ 。 4. 所以整串字节 0xE68891 被 latin1 字符集解释后的字符串就是 ‘我’ 可见,如果对于同一个字符串编码和解码使用的字符集不一样,会产生意想不到的结果,作为人类的我们看上去就像是产生了乱码一样。

字符集转换的概念 #

如果接收 0xE68891 这个字节串的程序按照 utf8 字符集进行解码,然后又把它按照 gbk 字符集进行编码,最后编码后的字节串就是 0xCED2 ,我们把这个过程称为 字符集的转换 ,也就是字符串 ‘我’ 从 utf8 字符集转换为gbk 字符集。

MySQL中字符集的转换 #

我们知道从客户端发往服务器的请求本质上就是一个字符串,服务器向客户端返回的结果本质上也是一个字符串,而字符串其实是使用某种字符集编码的二进制数据。这个字符串可不是使用一种字符集的编码方式一条道走到黑的,从发送请求到返回结果这个过程中伴随着多次字符集的转换,在这个过程中会用到3个系统变量,我们先把它们写出来看一下:

nameexplain
character_set_client服务器解码请求时使用的字符集
character_set_connection服务器处理请求时会把请求字符串从 character_set_client 转为 character_set_connection
character_set_results服务器向客户端返回数据时使用的字符集
show variables like 'character_set_client';
show variables like 'character_set_connection';
show variables like 'character_set_results';

大家可以看到这几个系统变量的值都是 utf8 ,为了体现出字符集在请求处理过程中的变化,我们这里特意修改一个系统变量的值:

mysql> set character_set_connection = gbk;
Query OK, 0 rows affected (0.00 sec)

# 所以现在系统变量 character_set_client 和 character_set_results 的值还是 utf8 ,而character_set_connection 的值为 gbk 。现在假设我们客户端发送的请求是下边这个字符串:
SELECT * FROM t WHERE s = '我';
# 为了方便大家理解这个过程,我们只分析字符 '我' 在这个过程中字符集的转换。

现在看一下在请求从发送到结果返回过程中字符集的变化:

  1. 客户端发送请求所使用的字符集一般情况下客户端所使用的字符集和当前操作系统一致,不同操作系统使用的字符集可能不一样,如下:

    • 类 Unix 系统使用的是 utf8
    • Windows 使用的是 gbk

    例如我在使用的 macOS 操作系统时,客户端使用的就是 utf8 字符集。所以字符 ‘我’ 在发送给服务器的请求中的字节形式就是: 0xE68891

    小贴士:如果你使用的是可视化工具,比如navicat之类的,这些工具可能会使用自定义的字符集来编码发送到服务器的字符串,而不采用操作系统默认的字符集(所以在学习的时候还是尽量用黑框框哈)。

  2. 服务器接收到客户端发送来的请求其实是一串二进制的字节,它会认为这串字节采用的字符集是character_set_client ,然后把这串字节转换为 character_set_connection 字符集编码的字符。由于我的计算机上 character_set_client 的值是 utf8 ,首先会按照 utf8 字符集对字节串 0xE68891 进行解码,得到的字符串就是 ‘我’ ,然后按照character_set_connection 代表的字符集,也就是 gbk 进行编码,得到的结果就是字节串 0xCED2 。

  3. 因为表 t 的列 col 采用的是 gbk 字符集,与 character_set_connection 一致,所以直接到列中找字节值为 0xCED2 的记录,最后找到了一条记录。

    小贴士:如果某个列使用的字符集和character_set_connection代表的字符集不一致的话,还需要进行一次字符集转换。

  4. 上一步骤找到的记录中的 col 列其实是一个字节串 0xCED2 , col 列是采用 gbk 进行编码的,所以首先会将这个字节串使用 gbk 进行解码,得到字符串 ‘我’ ,然后再把这个字符串使用 character_set_results 代表的字符集,也就是 utf8 进行编码,得到了新的字节串: 0xE68891 ,然后发送给客户端。

  5. 由于客户端是用的字符集是 utf8 ,所以可以顺利的将 0xE68891 解释成字符 我 ,从而显示到我们的显示器上,所以我们人类也读懂了返回的结果。

如果你读上边的文字有点晕,可以参照这个图来仔细分析一下这几个步骤:

从这个分析中我们可以得出这么几点需要注意的地方:

  • 服务器认为客户端发送过来的请求是用 character_set_client 编码的。假设你的客户端采用的字符集和 character_set_client 不一样的话,这就会出现意想不到的情况。比如我的 客户端使用的是 utf8 字符集,如果把系统变量 character_set_client 的值设置为 ascii 的话,服务器可能无法理解我们发送的请求,更别谈处理这个请求了。
  • 服务器将把得到的结果集使用 character_set_results 编码后发送给客户端。假设你的客户端采用的字符集和 character_set_results 不一样的话,这就可能会出现客户端无法解码结果集的情况,结果就是在你的屏幕上出现乱码。比如我的客户端使用的是 utf8 字符集,如果把系统变量character_set_results 的值设置为 ascii 的话,可能会产生乱码。
  • character_set_connection 只是服务器在将请求的字节串从 character_set_client 转换为character_set_connection 时使用,它是什么其实没多重要,但是一定要注意,该字符集包含的字符范围一定涵盖请求中的字符,要不然会导致有的字符无法使用 character_set_connection 代表的字符集进行编码。比如你把 character_set_client 设置为 utf8 ,把 character_set_connection 设置成 ascii ,那么此时你如果从客户端发送一个汉字到服务器,那么服务器无法使用 ascii 字符集来编码这个汉字,就会向用户发出一个警告。

知道了在 MySQL 中从发送请求到返回结果过程里发生的各种字符集转换,但是为啥要转来转去的呢?不晕么?

答:是的,很头晕,所以我们通常都把 character_set_client 、character_set_connection、character_set_results 这三个系统变量设置成和客户端使用的字符集一致的情况,这样减少了很多无谓的字符集转换。为了方便我们设置, MySQL 提供了一条非常简便的语句:SET NAMES 字符集名;

小贴士:如果你使用的是Windows系统,那应该设置成gbk。

SET NAMES 字符集名;
# 这一条语句产生的效果和我们执行这3条的效果是一样的:
SET character_set_client = 字符集名;
SET character_set_connection = 字符集名;
SET character_set_results = 字符集名;

# 另外,如果你想在启动客户端的时候就把 character_set_client 、 character_set_connection 、character_set_results 这三个系统变量的值设置成一样的,
# 那我们可以在启动客户端的时候指定一个叫 default-character-set 的启动选项,比如在配置文件里可以这么写:default character set 的启动选项,比如在配置文件里可以这么写:
[client]
default-character-set=utf8
# 它起到的效果和执行一遍 SET NAMES utf8 是一样一样的,都会将那三个系统变量的值设置成 utf8 。

比较规则的应用 #

结束了字符集的漫游,我们把视角再次聚焦到 比较规则 , 比较规则 的作用通常体现比较字符串大小的表达式以及对某个字符串列进行排序中,所以有时候也称为 排序规则 。比方说表 t 的列 col 使用的字符集是 gbk ,使用的比较规则是 gbk_chinese_ci ,我们向里边插入几条记录: 如果输入不了中文,参考 mysql安装

# 创建表t
CREATE TABLE t( col VARCHAR(10) ) CHARACTER SET utf8 COLLATE utf8_general_ci;

mysql> INSERT INTO t(col) VALUES('a'), ('b'), ('A'), ('B');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

# 我们查询的时候按照 t 列排序一下:
mysql> SELECT * FROM t ORDER BY col;
+------+
| col |
+------+
| a  |
| A  |
| b  |
| B  |
| 我  |
+------+
5 rows in set (0.00 sec)

# 可以看到在默认的比较规则 gbk_chinese_ci 中是不区分大小写的,我们现在把列 col 的比较规则修改为 gbk_bin :
mysql> ALTER TABLE t MODIFY col VARCHAR(10) COLLATE gbk_bin;
Query OK, 5 rows affected (0.02 sec)
Records: 5 Duplicates: 0 Warnings: 0

# 由于 gbk_bin 是直接比较字符的编码,所以是区分大小写的,我们再看一下排序后的查询结果:
mysql> SELECT * FROM t ORDER BY s;
+------+
| s |
+------+
| A |
| B |
| a |
| b |
| 我 |
+------+
5 rows in set (0.00 sec)

所以如果以后大家在对字符串做比较或者对某个字符串列做排序操作时没有得到想象中的结果,需要思考一下是不是 比较规则 的问题~

小贴士:列col中各个字符在使用gbk字符集编码后对应的数字如下:
‘A’ -> 65 (十进制)
‘B’ -> 66 (十进制)
‘a’ -> 97 (十进制)
‘b’ -> 98 (十进制)
‘我’ -> 25105 (十进制)


comments powered by Disqus