MySQL数据类型详解
字符串类型
char(n):定长的字符串
char(n)
存储范围是0-255个字节。这里所说的 字节数,其实就是存储数字、字母或者汉字的长度,只要存储字符串的长度在255这 个范围之内,都是可以的。也就是说,你可以存储长度为255的数字;你也可以存储长度为255的字母;或者说你还可以存储长度为255的中文。
当存储的字符串长度,没有超过n的时候,系统会用空格在末尾自动补齐到n。但是当char类型的数据被检索的时候,尾部补齐的空格,会首先被删除后,再显示。
char数据类型在进行存储的时候,可能会造成资源浪费。但是由于是定长存储,因而查询效率高。
varchar(n):不定长的字符串
无论是存储数字、字母还是汉字,都可以存放n个字符, 这里所说的n,其实也是表示能够存储的字符串的长度为n。varchar存储的最大长度受限于最大行长度,这个和字符编码也有一定的关系,比如说gbk
编码和utf8
编码,varchar存储的最大长度也会有所不同。(不理解这句话也无关紧要)
但是不管怎么说,varchar存储长度为20000的的字符串还是没有问题的。具体来说,当你设置的是utf8
编码的时候,最大行长度只能是21845,也就是说,你存储的字符串行长度最大也就是21845。这里存储varchar数据类型,需要预留1-2个长度,用于记录该字符串的实际存储长度,为以后读取该字符串做准备。因此实际上你能存储的字符串长度小于21845。
上面说的是什么意思呢?
由于varchar存储的变长的字符串,我们就拿varchar(5)来说,你可以存储长度为1的字符串,你也可以存储长度为2的字符串,…,你也可以存储长度为5的字符串。由于varchar是变长的,实际占据的空间大小由内容决定。因此,当你想要读取这个字符串的时候,系统怎么知道你是1个长度?是2个长度?还是5个长度呢?因此,对于varchar存储的变长的字符串来说,都会在其存储的实际长度之前,预留1-2个字节,用来记录这个字符串的实际长度,请看下图。
char和varchar存储的空间利用率比较
假如使用的是char数据类型存放字符串。实际存放的长度 i 肯定是小于等于实际的长度 N 的,当我们存储的长度正好为 N 时,那么空间的利用率为100%。
假如使用的是varchar数据类型,存放字符串。当存放的字符串长度为 i ,系统为了能够正确读取该字符串的长度,会在该字符串前方预留 1-2 个字节,用来记录该字符串的实际长度,因此,实际占用空间大小为 i +(1-2)。所以空间利用率怎么都是小于100%的。
tinytext、text、longtext
char最多可以存放长度为255的字符串,varchar最多存放长度为20000多的字符串。假如我们要存储一篇文章(字数很多),上面的数据类型,肯定是不能满足满足我们的需求,这就需要我们根据实际情况使用如下的类型:
-
tingytext
:存放字符型数据,最多可以存放255个字符。 -
text
:存放字符型数据,最多可以存放65536个字符。 -
longtext
:存放字符型数据,最多可以存放4294967295个字符。
注意:只要存放的是字符串类型,都要注意编码问题,一般使用的是utf8编码。
整数类型
我们要知道:1bytes = 8bit,也就是说一个字节表示8个比特位,而每一个比特位就是计算机中常说的0,1指令。
通常情况下,一个字节表示8个比特位,即由8个0,1数字组成的二进制数,最高位属于符号位(位于8个比特位的最左边的那个位数),该位用来标识正负数,如果该位是0表示的是正数,1表示的是负数。
因此,有符号位可以表示 0 和 正负数;无符号位(unsigned
)只能表示非负数。
整型数据类型声明时的参数问题
因为整数数据类型有2种取值范围,有符号和无符号的取值范围,我们在建表的时候,需要根据实际情况选择使用有符号,还是使用无符号。
比如说,存储一个age年龄字段,因为人的年龄都是大于0的。因此我们肯定是选择tinyint无符号,这个范围是[0,255],已经够我们存储人的年龄了。但是我们要怎么样表示,才能够让计算机知道我们想要使用有符号
和无符号
呢?
这就需要在声明字段数据类型的时候,使用合适的参数。整数数据类型在声明字段的时候,共有3个可选的参数,分别是:unsigned
、M
和zreofill
。下面我们分别对其进行一一说明。
注意:当我们不加任何参数,默认是使用的有符号的范围。
unsigned参数
-- 创建表
create table person(
pname varchar(20),
page tinyint unsigned,
psex bit(1)
) charset=utf8;
-- 插入两条记录
insert into person
(pname,page,psex)
values
("张三",18,0),
("李四",22,0);
观察下图:
观察上图的结果可以发现:page的数据类型,我们使用的是unsigned
无符号修饰的tinyint数据类型。
我们已经知道了,tinyint数据类型有符号取值范围是[-128,127],无符号取值范围是[0,255]。
因此当我们插入第一条数据,让page=-5
的时候,出现了out of range
越界的错误。当插入第二条数据,让page=255
的时候,处在正常范围之内,所以插入数据成功。
这个演示也说明了:当数据类型不加上unsigned
参数修饰,表示的是有符号的取值范围。假如你想要使用无符号的取值范围,就必须给数据类型添加一个unsigned
的参数修饰。
zerofill参数
zerofill参数必须和M参数配合使用"才有意义"。
-- 对学号字段进行一个说明:
-- 1:学号不能为负;
-- 2:学号一般位数相同,即使不同,也会用0填充。
-- eg:00001,00013,00128,01280。
-- 创建表
create table student(
sid smallint(5) zerofill not null default 0,
sname varchar(20),
sage tinyint unsigned,
ssex bit(1) default 0
) charset=utf8;
-- 插入两条记录
insert into student(sname,sid)
values ("张飞",5),("吕布",1);
观察下图:
观察上图中的结果:sid学生学号的数据类型,我们配合使用M
参数和zerofill
参数。接着我们向其中插入了两条数据,分别是吕布 sid=1
和张飞 sid=5
。
然而,当我们查看结果的时候,可以发现吕布的sid变成了00005
,张飞的sid变成了00001
。
总结如下:zerofill表示用0填充,M表示补0的宽度,这两个参数只有配合使用才会有意义,分开使用的意义不大。还是要记住一点,数据类型用zerofill参数修饰,则必定是unsigned的。
浮点数和定点数
关于浮点数:
- float(m,n):单精度,可以精确到小数点后8位。
- double(m,n):双精度,可以精确到小数点后16位。
关于定点数:
- decimal(m,n):货币类型。m表示总的位数,n表示小数位数。(n <= m)
注意:定点是把整数部分和小数部分分开进行存储的,比float、double更精确。
-- swage代表工资;sbonus代表津贴,津贴不能是负数。
-- 创建表
create table salary(
sname varchar(20),
swage float(6,2),
sbonus float(5,2) unsigned not null default 0
) charset=utf8;
-- 插入两条记录
insert into salary
(sname,swage,sbonus)
values
("纪晓岚",9999.99,111.11),
("和珅",-9999.99,444.44);
观察下表:
观察上面的表结构:swage的数据结构是float(6,2)
。sbonus的数据结构是float(5,2) unsigned
。
在swage中,我们即可以插入正数,也可以插入负数,不会有任何问题。而sbouns使用了unsigned
参数修饰,就只能表示非负数了。当我们向其中插入负数的时候,就会出现out of range
越界的错误。
上述演示操作也说明了:在小数数据类型中,我们也可以使用unsigned参数。
float/double和decimal精度比较
-- 创建表
create table bank(
id varchar(20),
acc1 float(9,2),
acc2 decimal(9,2)
) charset=utf8;
-- 插入两条记录
insert into bank(id,acc1,acc2)
values
(1,1234567.45,1234567.45),
(2,1234567.678,1234567.678);
观察下图:
观察上图中的结果:acc1的数据类型是float(9,2)
,acc2的数据类型是decimal(9,2)
。
我们总共是插入了两条记录,每条记录中的值都保持一样,其中一条记录插入的数据有两位小数,另外一条记录插入的数据有三位小数。
最后查看数据的时候,却发现很大的精度差别,相比之下还是decimal
数据类型的精度更高。你始终要记住,当插入和货币
相关的数据,就要严格注重数据的精度问题,建议使用decimal
。
日期/时间类型
什么是日期类型和时间类型
- 日期类型:指的是年、月、日,类似于2020-11-16(2010年11月16号)
- 时间类型:指的是时、分、秒,类似于10:45:30(10点45分30秒)
日期/时间类型
datatime标准格式:YYYY-MM-DD HH:MM:SS
- 占用8字节,混合类型,表示的是"年-月-日 时:分:秒"。
- 时间范围:[1000-01-01 00:00:00,9999-12-31 23:59:59]
timestamp(时间戳)
- 占用4字节,混合类型,表示的是"年-月-日 时:分:秒"。
date标准格式:YYYY-MM-DD
- 占用3字节,日期类型,表示的是"年-月-日"。
- 时间范围:[1000-01-01,9999-12-31]
time标准格式:HH:MM:SS
- 占用3字节,时间类型,表示的是"时:分:秒"。
- 时间范围:[00:00:00,23:59:59]