MySQL:MySQL的数据类型

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

一、数值类型

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是一个条件判断,所以如果我们想要两个都满足的话,我们只需要用一个逻辑与就可以解决这个问题了!!

相关推荐
0xDevNull14 分钟前
MySQL数据冷热分离详解
后端·mysql
科技小花30 分钟前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸31 分钟前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain33 分钟前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希1 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神1 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员1 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java2 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿2 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴2 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存