MySQL:数据类型

MySQL:数据类型


数值类型

int类型

int类型包含以下五种:

类型 大小
tinyint 1 byte
smallint 2 byte
mediumint 3 byte
int 4 byte
bigint 8 byte

tinyint为例,创建一个含tinyint类型的表:

t1num列的类型就是tinyint,我们尝试对其插入数据,来测试其范围。tinynt1 byte,那么就可以表示256个数字。

先试试是否带符号:

成功插入了-1,说明tinyint默认是有符号的。其实整个int家族,默认都是带符号的。

如果想要不带符号,建表时在类型的末尾后紧跟unsigned

这次再尝试插入-1

此时报错:out of range,不允许插入负数值了。

tinyint有符号时,存储范围是[-128, 127];无符号时,范围是[0, 255]。其它int家族的成员同理。


bit类型

顾名思义,bit类型就是自己指定比特位的数目。

语法:

sql 复制代码
bit(M)

其中M表示比特位的数目,如果省略(M)则默认表示一个比特位,M的取值范围是[1, 64]

示例:

t3表有两列,分别是idonlineonline的类型是bit(1)(也可省略为bit),即只占用一个比特位。

分别对online插入0, 1, 2,发现01可以正常插入,但是2不行,因为一个比特只能表示01

输出一下刚才插入的值:

奇怪的事情发生了,刚刚我们慢慢插入的是01,怎么online这一列没有显示?

bit类型在输出时,默认以ASCII码的形式展示,而01ASCII码中是控制字符,不可输出,所以我们看不到!

比如我现在将bit(1)改为bit(10),然后插入数字97

可以看到,最后数字97输出时,输出的是97对应的字符'a'


浮点类型

float / double

floatdouble用于存储浮点型,也就是小数,占用内存如下:

类型 大小
float 4 byte
double 8 byte

语法:

sql 复制代码
float(m, d) [unsigned]

其中m指定浮点数的总长度,d指定小数位数。

比如float(4, 2),表示整个浮点数占4位数字,小数点后占2位,也说明了小数点前的数字位数是4 - 2 = 2位,存储范围是[-99.99, 99.99]

如果希望存储无符号的数字,那么就是float(4, 2) unsigned,但是与整数不同,unsigned对浮点数只影响最小值为0,最大值不变,此时存储范围变成[0, 99.99]

浮点数的存储还有一些其它特性,我通过案例讲解。

首先创建一张表,其中第二列num的类型是float(4,2)

首先插入两个边界值:

99.99正常插入了,但是100超出范围了,可见99.99是边界值。

如果小数点后位数不够会发生什么?插入一个整数50,以及一个小数点后只有一位的10.5试试:

可知:当小数点后位数不足时,自动补0到精度。

那么如果小数点后面的位数超过了呢?再插入10.12310.456试试:

可知:当小数点后超出精度,此时发生四舍五入。

再尝试插入99.99499.995试试:

奇怪的事情发生了:99.994可以插入,但是99.995超出范围了,这是为什么?

这是因为99.994超出精度,四舍五入成99.99,刚好是可以存储的最大值。而99.995四舍五入成100.00,此时超出范围,不允许存储了!

float可以不指定(m, d),此时直接使用 float 不会强制保留固定数量的小数位,而是更具输入的数字实时调整。

可以看到,123.456有三位小数,正常保存了。而456.78910有五位小数,只保留了两位。这可以体现两个特点:

  1. 直接使用float,数字的位数可以根据插入的值自由调整
  2. 对于精度较高的数字,无法很好的保存,会四舍五入

一般来说,float的精度是7位十进制数字,包括小数点前后。而456.789108位数字,所以发生了精度损失。

在插入较大的整数时,整数也会有损失,比如插入123456789

只有最大的123456被存储了,而超出精度的789被四舍五入了,导致6变成了7,最后存储的值为123457

doublefloat同理,不过多赘述了。


decimal

从刚刚的float讲解可以看出:floatdouble会有精度损失,不适合存储对精度要求高的小数,因此MySQL推出了decimal类型,专门用于存储高精度要求的浮点数。

decimal的语法与float / double完全一致:

语法:

sql 复制代码
decimal(m,d) [unsigned]

decimal最大的m65,最大的d30。如果省略m,则默认m=0,如果省略d,则默认d=10

在使用上,decimalfloat / double没有任何区别。

案例:

创建了一个表格t6,其第二列num类型为decimal(10,8),也就是可以存储8位精度的小数。

插入12.3456789,没有任何精度损失。如果对于float,此时已经四舍五入了。

这是因为,decimal类型占用的空间不是固定的,其会根据精度的需要,调整占用的内存,确保可以精确保存这个精度的所有值!


字符串类型

MySQL中,字符串使用了charvarchar来存储,与大部分编程语言不同,编程语言中char往往只存储一个字符。

char

char用于存储固定长度的字符串。

语法:

sql 复制代码
char(L)

L用于指定字符串的最大长度,L的最大值为255

示例:

创建了一个第二列str类型为char(3)的表,现在插入一些值:

字符串'a''ab''abc'都插入成功了,而'abcd'超出了长度,插入失败。

再尝试插入汉字:

字符串'中国人'插入成功了,根据utf8编码规则,普通字母占1 byte,而汉字占3 byte。在部分编程语言中,例如C/C++,汉字算作三个字符,但是MySQL中认为一个汉字也是一个字符!


varchar

语法:

sql 复制代码
varchar(L)

L用于指定字符串的最大长度,L的最大值为不确定,但是最大字节数为65535

varchar是变长字符串,但是char本身就可以在限定范围内实现任意长度字符串存储,那么varchar的意义是什么?

对于char来说,如果指定了字符串的长度,那么存入的所有字符串都是这个长度所占字节的大小。比如说用char(20)存储字符串'abc',虽然只存储了三个字符,但是实际上还是会开辟20个字符的空间。

对于varchar来说,只要存入的字符串没有超过指定长度,那么该字符串占用多少内存,就实际开辟多少内存!

经过计算,若以utf8编码,varchar最大能存储65535 / 3 = 21845个字符。

尝试创一个varchar(21845)类型的列的表:

此时发生了报错,显示:This includes storage overhead,这是啥意思呢?

这是因为varchar类型每个字符串占用的字节数不确定,所以读取内存时,不知道这个字符串读取到啥时候结束,所以在整个字符串的首部,需要开辟1 - 3 byte,来存储这个字符串的长度。总共有65535 byte,减去首部占用的3 byte,最后能用的只有(65535 - 3) / 3 = 21844个字符。

可以看到,varchar(21844)utf8编码下的最大长度。

但是如果是其它编码,varchar所能表示的字符串长度还会有变化,比如gbk编码一个字符占用2 byte,最后能存储的最大长度就是:(65535 - 3) / 2 = 32766个字符。


日期时间类型

MySQL中,日期与时间也有专门的类型来存储,包以下三种:

类型 含义 格式 大小
data 日期 yyyy-mm-dd 4 byte
datetime 日期 + 时间 yyyy-mm-dd HH:ii:ss 8 byte
timestamp 时间戳 yyyy-mm-dd HH:ii:ss 4 byte

示例:

创建了表格t9,内部同时包含datedatetimetimestamp三种类型。

通过desc可以看到,timestamp的默认值DefaultCURRENT_TIMESTAMP,也就是当前的时间。

尝试对time1time2进行插入:

time1time2都按照正常格式插入了,与之同时time3自动更新为了当前时间。一般来说timestampdatetime没有格式上的区别,但是由于timestamp会自动更新,所以一般用于保存最后一次的修改时间。


enum & set

enum为枚举类型,用于进行单选。

语法:

sql 复制代码
enum('选项1', '选项2', '选项3', ...)

set为集合类型,用于进行多选。

语法:

sql 复制代码
set('选项1', '选项2', '选项3', ...)

示例:

现在创建了表t10,其第二列gender为枚举enum,第三列hobby为集合set。通过desc可知,enumset都允许为NULL

比如只插入name,此时genderhobby就为默认值NULL

在插入enum时,直接通过字符串来指定一个选项,而在插入set时,多个选项用逗号隔开:

张三有多个爱好,此时多个选项用逗号隔开:'篮球,羽毛球'

那么对于enumset来说,底层真的使用字符串来存储各个值的吗?如果用字符串存储,一个选项就要占用好几个字节,未免太低效了,它们底层都使用数字来存储。

  • enum中,选项从前往后分别用数字1,2,3,4,5...表示,最大值为65535
  • set中,选项通过位图存储,第一个选项为二进制1,第二个选项为二进制10,第三个选项为二进制100,以此类推,最多64个选项

在插入时,不仅可以用字符串来表示选项,也可以用数字来表示一个选项。

比如enum('男','女','保密')中,'男' = 1'女' = 2'保密' = 3set('羽毛球','乒乓球','篮球','足球') 中,'羽毛球' = 1'乒乓球' = 2'篮球' = 4'足球' = 8

在插入时,如果想选中'羽毛球,足球',就可以插入8+1=9

实验一下:

插入的值2对应了'女'9对应了'羽毛球,足球'

对于set,多选包括不选,插入空字符串'',或者数字0都可:

此处要注意,空串表示啥也不选,此处表示这个人没有任何爱好。而NULL表示缺少这个值,此处表示这个人的爱好不确定。


相关推荐
刘大浪7 分钟前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
无敌岩雀14 分钟前
MySQL中的索引
数据库·mysql
a_安徒生37 分钟前
linux安装TDengine
linux·数据库·tdengine
东阳马生架构39 分钟前
MySQL原理简介—1.SQL的执行流程
mysql
程序员学习随笔40 分钟前
PostgreSQL技术内幕19:逻辑备份工具pg_dump、pg_dumpall
数据库·postgresql
尘浮生1 小时前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
偶尔。5351 小时前
什么是事务?事务有哪些特性?
数据库·oracle
安迁岚1 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验六 视图
数据库·sql·mysql·oracle·实验报告
xoxo-Rachel1 小时前
(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
java·数据库·mysql
JH30732 小时前
Oracle与MySQL中CONCAT()函数的使用差异
数据库·mysql·oracle