
数据类型分类:(标红的是较为重要的)

一、数值类型

1.1 tinyint
在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的。
可以通过UNSIGNED来说明某个字段是无符号的
正常去插入:
数值越界测试:

和语言的区别:
1、语言定义变量的时候是类型在前,变量名在后,而mysql在表中建立属性列是列名称在前,类型在后,和语言是反过来的!!

2、如果是语言出现这种数据问题的不合法问题可能会发生截断,但是mysql他为了保证数据的完整性是不会做这种截断的操作的,而是会直接把你给拦截不让你做对应的操作!!
------>所以反过来,一旦我们有数据已经被成功插入到数据库中,那么这个数据必然也是合法的!
------>所以在mysql中,数据类型本身也是一种约束

注意:
1,尽量不使用unsigned,对于int类型可能存放不下的数据,int unsigned同样可能存放不下,与其如此, 还不如设计时,将int类型提升为bigint类型。
2,当然也要看具体的场景,比如说年龄不可能有负数,所以用unsigned int本身也是很合理的。
问题:为什么mysql要有这么多大小不一的数据类型呢??
------>为了满足不同的应用场景中和节省资源中做一个平衡,所以也不能无脑选最大的!
1.2 bit
bit[(M)] : 位字段类型。M表示每个值的位数,范围从1到64。如果M被忽略,默认为1。

使用案例:
因为只有一个bit位,所以你只能插入0或者1,一但超过也会被mysql约束

我们发现我们online插入显示不出来,这是因为online是bit类型,BIT类型的数据在MySQL中以二进制形式存储,默认是按照ascii码值的形式显示出来
当我们修改bit位数后,然后插入97,我们就会发现显示的是'a' (默认显示的是ascii值,可以用特定的内建函数去按照我们想要的进制去显示)
但是如果插入的是130,ascii无法显示,就表示不出来了。

需要使用特定的方法才能将其转换为可读的格式。在select语句中无法直接查看其值。要查看bit字段的值,我们可以使用MyL内置函数****BIN() 二进制 或 OCT() 八进制 或HEX() 十六进制




如果我们有这样的值,比如性别,这时可以定义bit(1),只存放0或1。这样可以节省空间。
1.3 浮点类型float
float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4个字节 (精度是6-7)
要注意M必须>=D
使用案例:


关于m和d的探究:

99.999插入不进去倒还好理解,可我们会发现99.9插入后变成了99.90,小数位用0补齐了,但是100.0也是4位数却不可以,这是因为他小数部分需要2位,所以如果补0了就变成5位了就不符合要求了!!所以我们会发现**(4,2)的范围是-99.99----99.99**

我们会发现刚才99.999不行,但是99.991却可以,这是因为MySQL在保存值时对多余的位不会无脑拦截,而是会先进行四舍五入,只有四舍五入后会导致位数变多的情况才会拦截
总结上面的情况,我们会发现其实mysql并不是无脑拦截,而是对于小数部分缺的会先尝试补0,多的会先尝试四舍五入,如果之后还不符合要求,才会拦截,比如100.0 99.95 所以更详细的范围应该是-99.994444444444......-------99.994444444444......。(即使我们用的是unsigned 他的上限也是不会变的,而负数部分会直接变成非法数据)
注意:浮点数存的时候也是转化成科学计数法然后进行存储的,有符号位、指数位、精度位,任何一个浮点数在转化的过程中不一定都能很精确地转化(因为精度位可能会存不下)。其次将浮点数转化成二进制的时候对于小数部分进行乘2取整也不一定所有的部分都能转化成0。 所以是很有可能会有部分精度丢失
double是比float精度还大的浮点数(15-16),占8个字节。
1.4 浮点类型decimal
decimal(m, d) [unsigned] : 定点数m指定长度,d表示小数点的位数
decimal(5,2) 表示的范围是 -999.99 ~ 999.99
decimal(5,2) unsigned 表示的范围 0 ~ 999.99 decimal和float很像,但是有区别:float和decimal表示的精度不一样

float表示的精度大约是7位。
decimal整数最大位数m为65。支持小数最大位数d是30。如果d被省略,默认为0.如果m被省略,默认是10。
建议:如果希望小数的精度高,推荐使用decimal。
二、字符串类型
2.1 char
char(L): 固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255

char(2) 表示可以存放两个字符,可以是字母或汉字,但是不能超过2个, 最多只能是255

char的单位是字符,这里的字符和我们以往语言的字符(1个字符占1个字节,utf8中按道理一个汉字要占3个字节)概念不一样,而是真的就是一个字符!无论是123 abc还是汉字 其实都算一个字符!
2.2 varchar
varchar(L): 可变长度字符串,L表示字符长度,最大长度65535个****字节

表面上看起来好像和char没啥区别,但是实际上是有区别的!!如下你会发现max竟然变成了21845!!这是为啥呢??------>varchar最大长度65536的单位是字节!!

关于varchar(len),len到底是多大,这个len值,和表的编码密切相关:
varchar长度可以指定为0到65535之间的值,但是有1 - 3 个字节用于记录数据大小,所以说有效字节数是65532。
当我们的表的编码是utf8时,varchar(n)的参数n最大值是65532/3=21844[因为utf中,一个字符占用3个字节],如果编码是gbk,varchar(n)的参数n最大是65532/2=32766(因为gbk中,一个字符占用2字节)。

其实这个21845也不对,他没有考虑记录数据大小的那几个字节,实际utf8最大应该是21844.
问题1:关于变长和定长的理解:
char类型就有点像静态数组,你定义多少我就给你多少空间,这就是定长的含义!!而varchar就有点像string类型,string会有一个char*指向该字符串,一个size表示该字符串有多少字符,一个capacity表示该字符串的上限,你需要多少空间就开辟多少空间,但是你一定不可以超过capacity,所以varchar括号后面表示的是他的字符上限,并不代表他真的开了这么多空间,他也会像string一样会有一部分空间来维护相关的信息,所以这就是变长的含义!!!
问题2:utf8最大字节数是21844,那为什么刚刚t10可以创建,但是t9不让创建呢?? 因为表的存储是一行一行存的,而一行存储最大的字节数也是65536,t10只有varchar类型所以可以一行都用来存varchar,因此可以达到最大的21844,但是t9还有一个int类型,所以要分出一部分空间给int,因此不能达到21844. 但如果我们减到21842,也是可以创建的

2.3 varchar和char的比较和选择
1、如果我们存储的是短字符串且大小比较均匀,那么使用char其实会更好一点(因为还需要额外一部分字节来保存有效长度),但是其他情况(字符串较长且大小不均匀)的话使用varchar会好些。
2、varchar具体需要多少个字节来存有效长度(1-3)是要根据实际情况动态调整的,像上图的短字符串其实只要一个字节就够了
问题总结:如何选择定长或变长字符串?
1、如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5
如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去。
2、定长的磁盘空间比较浪费,但是效率高。
变长的磁盘空间比较节省,但是效率低。(需要维护一些字段,而且动态开辟空间耗时)
3、定长的意义是,直接开辟好对应的空间
变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。
2.4 日期和时间类型
常用的日期有如下三个:
date :日期 'yyyy-mm-dd' ,占用三字节(存储一个不需要时间的日期,比如生日、各种节日)
datetime 时间日期格式 'yyyy-mm-dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用八字节(存储一个静态的、不会随修改而更新的时间,比如入职时间、身份证过期时间**)**
timestamp :时间戳,从1970年开始的 yyyy-mm-dd HH:ii:ss 格式和 datetime 完全一致,占用四字节(存储一个需要随着修改而更新的时间,比如评论、修改文章)
timestamp默认的是当前的时间戳,而当你进行增加或者更改的时候,他会立马更新成当前的时间戳!(动态)!而前两种需要程序员自己设定格式且是静态的!!
因为timestamp会自动更新时间戳t3,不需要我们插入,因此我们只需要插入t1和t2, 这个时候我们的括号就不能省略了,因为省略的话默认是全都要插入
当我们改掉t1的时候,t3也跟着变了

timestamp的典型应用场景:评论
首次评论

修改评论

2.5 enum和set
enum:枚举,"单选"类型;
enum('选项1','选项2','选项3',...);
该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;而且出于效率考虑,这些值实际 存储的是"数字",因为这些选项的每个选项值依次对应如下数字:1,2,3,....最多65535个;当我们添加枚举值时,也可 以添加对应的数字编号。
set:集合,"多选"类型;
set('选项值1','选项值2','选项值3', ...);
该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值;而且出于效率考虑,这些值 实际存储的是"数字",因为这些选项的每个选项值依次对应如下数字:1,2,4,8,16,32,.... 最多64个。
说明:不建议在添加枚举值,集合值的时候采用数字的方式,因为不利于阅读
案例: 有一个调查表votes,需要调查人的喜好, 比如(代码、羽毛球、乒乓球、足球、游泳)中去选择(可以多选),(男,女)[单选]

我们会发现插入1和2是可以的,因为单选对应的数字是从1-65535,所以男是1,女是2

爱好是多选的,所以一个人可以插入多个爱好

NULL vs ' ' 的区别:NULL是什么都没有,而' '是有只不过是空串 (前者就是你没有银行卡,后者就是你有银行卡但是里面没钱)

我们输入3的时候按单选的道理是乒乓球,但实际上确实羽毛球、代码 !!这说明其实多选每个选项代表的是一个bit位 比方说我们有五个多选,就是00000 每一位是0还是1代表这个爱好是否选择,比如3就是00011 说明代码和羽毛球被选了,而7就是00111,就是代码、乒乓球、羽毛球被选了。

所以单选是下标,多选是位图!!
2.6 enum和set的类型查找
enum的查找

但是多选就不适用了,比如我想找到会所有会打羽毛球的人,但是这样只会给我筛选出只会打羽毛球的人

所以集合查询使用find_ in_ set函数:
find_in_set(sub,str_list) :如果 sub 在 str_list 中,则返回下标;如果不在,返回0; str_list 用逗号分隔的字符串。
select find_in_set('a', 'a,b,c')

查找会打羽毛球的人 select * from votes where find_in_set('羽毛球', hobby);

如果我们想查找会代码和羽毛球的,直接写到find_in_set里面是不可以的,因为他其实只能判断其中一个是否在集合里,不能判断两个。
但是因为where是一个条件判断,所以如果我们想要两个都满足的话,我们只需要用一个逻辑与就可以解决这个问题了!!

