vlambda博客
学习文章列表

带你学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) 整数类型
带你学MySQL系列 | MySQL数据类型详解

符号位与无符号位详解网址:

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个可选的参数,分别是:unsignedMzreofill。下面我们分别对其进行一一说明。

注意:当我们不加任何参数,默认是使用的有符号的范围。

② 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);

观察下图:

带你学MySQL系列 | MySQL数据类型详解

观察上图的结果可以发现: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(1default 0
charset=utf8;

-- 插入两条记录
insert into student(sname,sid)
values ("张飞",5),("吕布",1);

观察下图:

带你学MySQL系列 | MySQL数据类型详解

观察上图中的结果: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,2unsigned not null default 0
charset=utf8;

-- 插入两条记录
insert into salary
(sname,swage,sbonus)
values
("纪晓岚",9999.99,111.11),
("和珅",-9999.99,444.44);

观察下图:

带你学MySQL系列 | MySQL数据类型详解

观察上面的表结构: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);

观察下表:

带你学MySQL系列 | MySQL数据类型详解

观察上图中的结果: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]