文章目录
- [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);

















































