带你学MySQL系列 | MySQL数据类型详解
1.简要概述
为什么要开通MySQL这个学习板块呢?因为这是一名数据分析师必要的一项技能。分析数据什么最重要?当然是数据,既然如此!在数据呈现爆发式增长的年代,怎么能够不学学数据库呢?其实这也是很多读者朋友希望看到的,也是他们建议我写的。
难者不会,会者不难!其实网上很多MySQL的总结文章,不可否认,知识点写的都很全,但是呢!这个只是会使用MySQL数据库的朋友的一个查询手册,不会使用的还是不会使用呀(并没有详细的介绍)。于是我就开始了我这个板块的写作,希望能够帮助那些转行的,要学习MySQL的朋友们。当然还要补充一点,这些板块并不是针对那些搞开发的、想当DBA的朋友,而是针对那些转行数据分析,然后需要学习MySQL数据库的那些朋友们。
前面我们已经带着大家怎么安装了MySQL数据库了,我也相信我写的这个MySQL安装教程
应该是全网最详细的一个教程,不信你看。
当然,如果你此时正在为MySQL的二次安装(第一次安装失败)感到苦恼,那么这个MySQL的卸载文章
应该对你会有很大作用。
虽然我们不当DBA,但是适当了解一些MySQL增删改查以外的知识,也是有必要的,比如说建表语句为什么加上这个charset=utf8?
我们从输入SQL语句到服务器给我们返回数据,究竟经历了一个怎么样的历程?你就可以适当看看下面这篇文章。
2. MySQL数据类型详解
学过编程语言的人都知道,怎么学习一门编程语言呢?首先要从数据类型开始学起。虽然库是别人创建的,表是别人设计的,这些好像都与你无关,但是掌握这样一个知识点,对你更好的理解和学习MySQL,肯定是会有帮助的。
1) 字符串类型
① char(m):定长的字符串。
char(m)
很多地方说的存储范围是0-255
个字节。但是,我测试过这里所说的 字节数,其实就是存储数字、字母或者汉字的长度,只要存储字符串的长度在255这 个范围之内,都是可以的。也就是说,你可以存储长度为255的数字;你也可以存储长度为255的字母;或者说你还可以存储长度为255的中文。
当存储的字符串长度,没有超过m的时候,系统会用空格在末尾自动补齐到m。但是当char类型的数据被检索
的时候,尾部补齐的空格,会首先被删除后,再显示。
char数据类型在进行存储的时候,可能会造成资源浪费。但是由于是定长存储,因而查询效率高
。
② varchar(m):不定长的字符串。
无论是存储数字、字母还是汉字,都可以存放m个字符,这里所说的m,其实也是表示能够存储的字符串的长度为m。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肯定是小于等于实际的长度M的,当我们存储的长度正好为M时,那么空间的利用率为100%。假如使用的是varchar数据类型,存放字符串。当存放的字符串长度为i,系统为了能够正确读取该字符串的长度,会在该字符串前方预留1-2个字节,用来记录该字符串的实际长度,因此,实际占用空间大小为i+(1-2)。所以空间利用率怎么都是小于100%的。
④ tinytext、text、longtext
char最多可以存放长度为255的字符串,varchar最多存放长度为20000多的字符串。假如我们要存储一篇文章(字数很多),上面的数据类型,肯定是不能满足满足我们的需求,这就需要我们根据实际情况使用如下的类型。
tingytext
:存放字符型数据,最多可以存放255个字符。
text
:存放字符型数据,最多可以存放65536个字符。
longtext
:存放字符型数据,最多可以存放4294967295个字符。
注意:只要存放的是字符串类型,都要注意编码问题,一般使用的是utf8编码。
2) 整数类型
符号位与无符号位详解网址:
https://www.cnblogs.com/123ing/p/4135229.html
我们要知道: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参数必须和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的。
3)小数类型(浮点数和定点数类型)
对于浮点数
:
-
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
。
4)日期/时间类型
① 什么是日期类型和时间类型?
-
1)日期类型:指的是年、月、日,类似于2019-11-16(2019年11月16号) -
2)时间类型:指的是时、分、秒,类似于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]