【MySQL】数据类型(下)

文章目录

  • [1. 字符串类型](#1. 字符串类型)
    • [1.1 char(定长字符串)](#1.1 char(定长字符串))
    • [1.2 varchar(变长字符串)](#1.2 varchar(变长字符串))
    • [1.3 char 和 varchar比较](#1.3 char 和 varchar比较)
    • [1.4 如何选择?](#1.4 如何选择?)
  • [2. 日期和时间类型](#2. 日期和时间类型)
  • [3. enum和set](#3. enum和set)
    • [3.1 基本使用和理解](#3.1 基本使用和理解)
    • [3.2 enum和set的查找](#3.2 enum和set的查找)

1. 字符串类型

1.1 char(定长字符串)

语法:

cpp 复制代码
char(L): 固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255

案例:

先来创建一张表
create table t8( id int, name char(2));
表有两列,第一列id类型为int,第二列name类型为字符串,长度固定为2

那我们来插入一些数据

对于name这一列,因为它的长度是2,所以我们插入长度为1的字符串可以,2也可以,但是超过2就不行了
那刚才是英文的字符串,如果是中文呢?


创建表的时候我们没有指明字符集,所以使用默认字符集是utf8mb4,在utf8mb4下:
一个英文字符占1个字节
一个中文字符占3个字节(部分生僻字可能占4个字节)
🆗,那我们第一次插入两个英文字符就是2个字节,后面插入汉字两个汉字的话就占6个字节了,为什么还可以插入进去呢?
这里要说明一下:
MySQL中的一个字符和我们熟悉的C/C++的字符是不太一样的,C/C++中一个字符就是占一个字节(类型为char),MySQL中的一个字符真的就是代表一个符号,比如一个英文字符或一个中文字符,或一个数字

所以上面为什么能插入成功,因为一个汉字在MySQL中就是一个字符。
再往下,上面提到最大长度是255,我们来验证一下
create table t9( address char(256) );

1.2 varchar(变长字符串)

语法:

sql 复制代码
varchar(L): 可变长度字符串,L表示字符长度,最大长度65535个字节

使用语法呢和char一样,括号中的数字指定字符串的长度,最大长度为65535字节

举例:

先建表
create table t9( id int, name varchar(6) );

两列,第二列类型为变长字符串,长度为6
来插入一些数据


指定的长度是6,所以字符串最大长度为6,超过6不能插入了。
那到这一步,我们可能会感觉到,这好像跟char没什么区别啊?
到底有什么区别,我们后面介绍

下面我们来修改一下表结构:

上面提到varchar的最大长度是65535
我们来试一下,把name列改为varchar(65535)
alter table t9 modify name varchar(65535);

但我们发现报错了,他说最大长度是16383。
怎么回事?
🆗,仔细看,上面写的是65535字节

utf8mb4字符集中一个字符最多占用4个字节,所以最大字符数就是65535/4=16383.75,取整为16383
老一点的MySQL可能是21845(65535/3)
而且这个最大值和表的编码密切相关,采用不同的编码,这个最大值可能是不同的。

说明:

关于varchar(len),len的最大值和表的编码密切相关。
varchar最大长度为65535字节,但是有1 - 3 个字节用于记录数据大小(存的数据越多这里记录数据用的字节数也越多),所以说有效字节数是65532。所以上面报错说最大长度是16383,实际也不一定能真的开到这个值

1.3 char 和 varchar比较

那varchar叫做变长字符串,char是定长字符串,他们的区别到底是什么?

对于char来说,如果我们指定长度为4------char(4),定长的意思就是不论我实际插入了几个字符(比如这一列我只插入了一个'a'),我用的空间永远是4个字符的空间。(类似C/C++中的静态数组,比如char arr[4];)
而对于varchar来说,如果我也指定长度为4------varchar(4),如果我只插入一个字符,那就只分配一个字符的空间。
varchar就有点类似C++中的string

varchar(4)就表明我的容量是4(当然这里就没有动态扩容这一说了),只要不超过4,我放几个字符,就用几个字符的空间。

varchar加的1是什么?
上面提到的,varchar需要有1 - 3 个字节用于记录数据大小(存的数据越多这里记录数据用的字节数也越多)

1.4 如何选择?

如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5
如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去
定长的磁盘空间比较浪费,但是效率高。
变长的磁盘空间比较节省,但是效率低。
定长的意义是,直接开辟好对应的空间
变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。

2. 日期和时间类型

date

日期 'yyyy-mm-dd' ,占用3字节

datetime

时间日期格式 'yyyy-mm-dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用8字节

timestamp

时间戳,从1970年1月1日00时00分00秒开始总秒数,表示为 yyyy-mm-dd HH:ii:ss 格式和 datetime 完全一致,占用4字节

案例:

还是先来创建一张表
create table t10( t1 date, t2 datetime, t3 timestamp );

注意:老一点版本的MySQL中时间戳类型的默认值为CURRENT_TIMESTAMP,即当前时间戳
插入或修改的时候我们可以不管这一列,他会默认更新为当前的时间戳

不过我们看到当前我是用的MySQL时间戳类型的默认值为NULL


那我们可以手动设定一下它的默认值
alter table t10 modify t3 timestamp DEFAULT CURRENT_TIMESTAMP;

这样我们插入数据他就会自动更新为当前的时间戳

然后我来修改其它列的一下数据,是否也会像上面一下时间戳这一列会自动更新?

并没有

为什么不一样呢?

上面我们手动设定了时间戳的默认值为
但是还有一个地方不一样

extra这一列,现在我们还不知道这一列是什么。
这里设定为ON UPDATE CURRENT_TIMESTAMP的意思就是当行中的其他列被更新时,该TIMESTAMP列会自动更新为当前时间戳。
那我们可以再手动设置一下
alter table t10 modify t3 timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
然后再来修改其他列数据

这次时间戳就自动更新了(应用场景:比如在某个论坛发表评论,用户只发布或修改评论,此时时间戳可以自动更新为用户发布或修改的时间)

总结:

date就可以表示诸如生日这样的年月日信息,datetime是年月日+时分秒。这两个我们不修改它就不会自动变化。timestamp时间戳我们可以设置它在某些场景下自动更新为当前时间

3. enum和set

3.1 基本使用和理解

先来介绍一下enum------枚举,C语言里面我们也学过枚举

那MySQL里的枚举类型怎么使用呢?语法:

enum:枚举("单选"类型)

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

该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值 (多选一);而且出于效率考虑,这些值实际存储的是"数字",这些选项的每个选项值依次对应如下数字:1,2,3,...最大65535;当我们添加枚举值时,也可以添加对应的数字编号。(但是不建议采用数字的方式,因为不利于阅读
比如有个问卷,其中一道题问你今天星期几?选项有7个,但是只能选一个

enum只能从枚举的值中选一个,而 set可以选多个:

set:集合("多选"类型)

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

该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值 ;而且出于效率考虑,这些值实际存储的是"数字",因为这些选项的每个选项值依次对应如下数字:1,2,4,8,16,32,...最大64。
问卷的另一道题问你,你的爱好是什么,很多选项,你也可以选择一个或多个。

案例:有一个调查表votes,需要调查人的喜好, 在(登山,游泳,篮球,武术)中去选择(可以多选),其次调查性表(男,女)[单选]

建表:

create table votes( username varchar(30), gender enum('男','女'), hobby set('编程','跑步','听音乐','乒乓球','唱歌'));

然后我们来插入一些数据


这都没什么问题
上面还说,enum和set实际存的是数字,对于enum来说,里面的选项值依次对应1,2,3...
那这里1就应该对应男,2就应该对于女。我们来试一下

没毛病,就是这样
那可以插入选项以外的值吗?


不行,正常情况下除了1,2都是不行。不过可能由于版本的差异,有些版本下(比如MySQL 8.0.44)插入0,可能成功,但在结果中是空串

但是我们认为只能插入列举出来的选项中的值。(可以是枚举值,或者是对应的数字,从1开始)

下面再来重点看一下set这一列:

set有多个选项,而上面说了我们也可以插入多个
刚才都是一个,当然你如果插入给出的选项以外的值肯定也不行

但是某个人现在有多个爱好,set这一列怎么插入多个呢?

中间用逗号隔开即可,注意不要写成中文的逗号了
另外,如果我们只插入姓名,其余两列默认为空

那NULL和上面的插入0显示的空串''(里面没有空格)的区别是啥?

NULL就是空,啥也没有,而''是有东西的,只不过是空串。
就类似你没有建设银行卡和有卡但是里面没有钱的区别。

那再往下,set当然也可以用数字插入

它也是依次对应1,2,3...嘛
我们来试一下

并不是这样的,其实上文也已经提到了

对于set,每个选项值对应的数字依次为1,2,4,8...64
那3,5...这些值呢?
🆗,3=1+2,所以插入3,就是插入前两个(因为set可以插入多个值,所有选项里面选一个或多个)
这也就是为什么我们上面插入3,对应的是编程和跑步。
那我插入7就应该是前三个选项(7=1+2+4)

没有问题。

你可以这样理解:


现在set又5个选项,想象成5个比特位,第一个比特位就代表编程,第二个比特位代表跑步,依次类推(就像数据结构中的位图)
1就代表选中第一个比特位(编程),00001,就是1
2就代表选中第二个比特位(跑步),00010,就是2
那4->00100(听音乐)
8->01000(乒乓球)
16->10000(唱歌)
所以3->00011,就是编程+跑步

全选:11111,对应十进制31

所以,枚举enum可以认为是下标(从1开始),集合set可以认为是位图

3.2 enum和set的查找

关于查询,我们后面还会详细讲,这里主要还是帮助大家更好的理解这两个类型的特性。

案例:

表现在是这样的:

先来看枚举类型的查找

查找所有性别为男的
select * from votes where gender='男';(where后面跟的就是条件,类似C/C++中的if)

性别为女的

再来看set类型:

比如查找爱好为编程的

没有问题(当然也可以用数字),但是这里只查找了爱好只有编程的。

而有些人爱好有很多,不止一个,里面包含了编程,这些人我想查找出来怎么做呢?

集合查询使用find_ in_ set函数:
find_in_set(sub,str_list) :如果 sub 在 str_list 中,则返回下标;如果不在,返回0。
str_list 是用逗号分隔的字符串/set类型的列名。

案例:


那下面使用find_ in_ set函数来查询上面的表
我们来查找爱好有编程的人

爱好里面有编程和跑步的怎么查?
select * from votes where find_in_set('编程',hobby) and find_in_set('跑步',hobby);

相关推荐
阿拉伯柠檬2 小时前
MySQL复合查询
linux·数据库·mysql·面试
胖虎12 小时前
Android 文件下载实践:基于 OkHttp 的完整实现与思考
android·okhttp·下载文件·安卓下载·安卓中的下载
霖霖总总2 小时前
[小技巧28]MySQL 窗口函数详解:原理、用法与最佳实践
数据库·sql·mysql
e***98572 小时前
MySQL数据可视化全流程解析
数据库·mysql·信息可视化
2301_765715142 小时前
数据可视化:MySQL管理的视觉助手
数据库·mysql·信息可视化
_李小白2 小时前
【Android 美颜相机】第四天:CameraLoader、Camera1Loader 与 Camera2Loader
android·数码相机
00后程序员张2 小时前
iOS APP 性能测试工具,监控CPU,实时日志输出
android·ios·小程序·https·uni-app·iphone·webview
橘橙黄又青2 小时前
【无标题】
mysql
invicinble2 小时前
认识es的多个维度
android·大数据·elasticsearch