1. 字符集和校对顺序
数据库表被用来存储和检索数据。不同的语言和字符集需要以不同的方式存储和检索。因此,MySQL需要适应不同的字符集(不同的字母和字符),适应不同的排序和检索数据的方法。
在讨论多种语言和字符集时,将会遇到以下重要术语:
-
字符集为字母和符号的集合;
-
编码为某个字符集成员的内部表示;
-
校对为规定字符如何比较的指令。
补充:
-
校对为什么重要:
排序英文正文很容易,对吗?或许不。考虑词APE、apex和Apple。它们处于正确的排序顺序吗?这有赖于你是否想区分大小写。使用区分大小写的校对顺序,这些词有一种排序方式,使用不区分大小写的校对顺序有另外一种排序方式。这不仅影响排序(如用ORDER BY排序数据),还影响搜索(例如,寻找apple的WHERE子句是否能找到APPLE)。在使用诸如法文à或德文ö这样的字符时,情况更复杂,在使用不基于拉丁文的字符集(日文、希伯来文、俄文等)时,情况更为复杂。
在MySQL的正常数据库活动(SELECT、INSERT等)中,不需要操心太多的东西。使用何种字符集和校对的决定在服务器、数据库和表级进行。
2. 使用字符集和校对顺序
MySQL支持众多的字符集。
-
为查看所支持的字符集完整列表,使用以下语句:
show character set;
输出如下(未截全):
这条语句显示所有可用的字符集以及每个字符集的描述和默认校对。
-
为了查看所支持校对的完整列表,使用以下语句:
show collation;
输出如下(未截全):
此语句显示所有可用的校对,以及它们适用的字符集。可以看到有的字符集具有不止一种校对。例如,latin1对不同的欧洲语言有几种校对,而且许多校对出现两次,一次区分大小写(由_cs表示),一次不区分大小写(由_ci表示)。
-
通常系统管理在安装时定义一个默认的字符集和校对。此外,也可以在创建数据库时,指定默认的字符集和校对。为了确定所用的字符集和校对,可以使用以下语句:
show variables like 'character%'; show variables like 'collation%';
输出如下:
-
实际上,字符集很少是服务器范围(甚至数据库范围)的设置。不同的表,甚至不同的列都可能需要不同的字符集,而且两者都可以在创建表时指定。
为了给表指定字符集和校对,可使用带子句的CREATE TABLE:
create table mytable ( column1 int, column2 varchar(10) )default character set hebrew collate hebrew_general_ci;
此语句创建一个包含两列的表,并且指定一个字符集和一个校对顺序。
这个例子中指定了CHARACTER SET和COLLATE两者。一般,MySQL按如下确定使用什么样的字符集和校对。
-
如果指定CHARACTER SET和COLLATE两者,则使用这些值。
-
如果只指定CHARACTER SET,则使用此字符集及其默认的校对(如
SHOW CHARACTER SET
的结果中所示)。 -
如果既不指定CHARACTER SET,也不指定COLLATE,则使用数据库默认。
-
-
除了能指定字符集和校对的表范围外,MySQL还允许对每个列设置它们,如下所示:
create table mytable1 ( column1 int, colume2 varchar(10), column3 varchar(10) character set latin1 collate latin1_general_ci )default character set hebrew collate hebrew_general_ci;
这里对整个表以及一个特定的列指定了CHARACTER SET和COLLATE。
-
如前所述,校对在对用ORDER BY子句检索出来的数据排序时起重要的作用。如果你需要用与创建表时不同的校对顺序排序特定的SELECT语句,可以在SELECT语句自身中进行:
select * from customers order by cust_name collate latin1_general_cs;
此SELECT使用COLLATE指定一个备用的校对顺序(在这个例子中,为区分大小写的校对)。这显然将会影响到结果排序的次序。
插一句题外话
试了一下上面的select语句,结果报错
回归正题
补充:
-
临时区分大小写:
上面的SELECT语句演示了在通常不区分大小写的表上进行区分大小写搜索的一种技术。当然,反过来也是可以的
-
SELECT的其他COLLATE子句:
除了这里看到的在ORDER BY子句中使用以外,COLLATE还可以用于GROUP BY、HAVING、聚集函数、别名等。
-
-
最后,值得注意的是,如果绝对需要,串可以在字符集之间进行转换。为此,使用
Cast()
或Convert()
函数。
插句题外话
-
CAST()
函数CAST() 是 MySQL 中用于显式转换数据类型的函数。它可以将一个表达式(比如一个列值或常量)从一种数据类型转换为另一种数据类型。
语法:
CAST(expression AS target_data_type)
-
expression:表示需要转换的数据或表达式,通常是列名、常量值等。
-
target_data_type:目标数据类型,是要将 expression 转换成的类型。常见的目标数据类型包括 SIGNED(带符号整数)、UNSIGNED(无符号整数)、CHAR、DATE、DATETIME、DECIMAL 等。
常见的目标数据类型:
-
SIGNED:转换为有符号整数类型。
-
UNSIGNED:转换为无符号整数类型。
-
CHAR、VARCHAR:转换为字符类型(可以指定长度)。
-
BINARY、VARBINARY:转换为二进制数据类型。
-
DATE、DATETIME:转换为日期或日期时间类型。
-
DECIMAL、FLOAT、DOUBLE:转换为数字类型。
举几个例子:
-
将字符串转换为整数:
SELECT CAST('123' AS UNSIGNED);
这个查询会将字符串 '123' 转换为无符号整数 123。
-
将浮点数转换为整数:
SELECT CAST(123.45 AS SIGNED);
这个查询会将浮点数 123.45 转换为带符号整数 123。
-
将数字转换为字符串:
SELECT CAST(123 AS CHAR);
这个查询会将整数 123 转换为字符串 '123'。
-
将日期字符串转换为 DATE 类型:
SELECT CAST('2024-12-01' AS DATE);
这个查询会将字符串 '2024-12-01' 转换为 DATE 类型。
特点:
-
CAST() 主要用于数据类型之间的转换,不支持字符集转换。
-
语法简洁,常用于将一个数据类型转换为另一个类型,尤其是在进行数值计算或数据格式调整时。
-
对于日期、时间和字符数据类型的转换,CAST() 会自动进行格式化处理。
-
-
CONVERT()
函数CONVERT() 是一个功能更强大的函数,不仅支持数据类型转换,还支持字符集转换。它可以用于将一个值从一种数据类型转换为另一种数据类型,或在字符集之间进行转换。
语法:
CONVERT(expression, target_data_type)
或者
CONVERT(expression USING target_charset)
-
expression:表示需要转换的数据或表达式,通常是列名、常量值等。
-
target_data_type:目标数据类型,和 CAST() 类似,可以是 SIGNED、CHAR、DATE 等。
-
target_charset:目标字符集,只在字符集转换时使用,例如 utf8、latin1 等。
举几个例子:
-
将字符串转换为整数:
SELECT CONVERT('123' SIGNED);
这个查询会将字符串 '123' 转换为带符号整数 123。
-
将浮点数转换为字符串:
SELECT CONVERT(123.45, CHAR);
这个查询会将浮点数 123.45 转换为字符串 '123.45'。
-
将字符串从一个字符集转换为另一个字符集:
SELECT CONVERT('你好' USING latin1);
这个查询会将字符串 '你好' 从 UTF-8 编码转换为 latin1 编码,可能会导致字符丢失或乱码,因为 latin1 不能表示所有的 Unicode 字符。
-
将字段值转换为不同的字符集:
SELECT CONVERT(name USING utf8) FROM users;
这个查询将 users 表中的 name 字段值从当前字符集转换为 utf8 字符集。
特点:
-
CONVERT() 函数不仅支持数据类型转换,还可以进行字符集转换,尤其适用于需要转换字符串编码时。
-
在处理字符集转换时,CONVERT() 会尝试将字符串中的字符从一个字符集映射到另一个字符集。如果目标字符集无法表示某些字符,可能会丢失或出现乱码。
-
CONVERT() 在字符集转换时,可以在 USING 子句中指定目标字符集,支持的字符集包括 utf8、latin1、gbk 等。
对比:
-
CAST() 只支持数据类型转换,而不支持字符集转换。
-
CONVERT() 不仅可以进行数据类型转换,还可以在字符集之间转换。
-