🌈欢迎来到MySQL专栏
- 🌍博客主页 :张小姐的猫~江湖背景
- 🔥所属专栏 :MySQL实战
- 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

MySQL

一、数据类型分类

二、数值类型
大部分以整型为例

🌏tinyint类型
进行数值越界测试:
首先创建出一个表
sql
create table if not exists t1( num tinyint );
插入四个数
sql
insert into t1 values (-128);
insert into t1 values (127);
insert into t1 values (-1);
insert into t1 values (1);
插入越界情况:
sql
mysql> insert into t1 values (128);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into t1 values (-129);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
sql
+------+
| num |
+------+
| -128 |
| 127 |
| -1 |
| 1 |
+------+
在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的
建表时可以通过UNSIGNED来说明某个字段是无符号的
接下来进行无符号建表:
sql
create table t2(num tinyint unsigned);
紧接着进行插入数据【0,255】 ------ 无符号!
sql
mysql> insert into t2 values(-1);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into t2 values(0);
mysql> insert into t2 values(255);
mysql> insert into t2 values(256);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
也就是说要进行插入的数据范围超过了指定的类型 ,MySQL直接拦截!不会让你插入~
注意:未来在设置数据类型的时候,提供了这么多大小不一的整数!是为了满足应用场景和节省资源之间做平衡! 存年龄的话,就用无符号的
tinyint就足够了
所以MySQL中,一般而言,数据类型本身也是一种约束(约束使用者)! 倒逼程序员尽可能进行正确的插入
- 能保证数据库中的数据是有预期的,完整的!
🌏bit类型
基本语法:
bit[(M)] : 位字段类型。M表示每个值的位数,范围从1到64。如果M被忽略,默认为1。
创建一个表,位字段设置为1
sql
create table if not exists t3( id int, online bit(1) );
sql
insert into t3 values(123, 1);
insert into t3 values(123, 0);
insert into t3 values(124, 2);
ERROR 1406 (22001): Data too long for column 'online' at row 1
因为此时比特位为1位,只能插入0, 1 ,插入其他值都不符合会直接报错
但我们发现为什么插入的online的值不显示呢?
- 这里是按照
ascll码值去显示的,只是当前的ascll值是不可显示的!才看不见
sql
+------+--------+
| id | online |
+------+--------+
| 123 | |
| 124 | |
+------+--------+
想要看见online的值可以按照十进制的方式进行打印
sql
mysql> select id, hex(online) from t3;
+------+-------------+
| id | hex(online) |
+------+-------------+
| 123 | 1 |
| 124 | 0 |
+------+-------------+
我们往里插入65和97,看看它是否会显示出来 A 和 a ?
sql
+------+--------+
| id | online |
+------+--------+
| 123 | |
| 124 | |
| 124 | |
| 124 | A |
| 124 | a |
+------+--------+
🌏小数类型
🔥float
语法:
sql
decimal(m, d) [unsigned]
定点数m指定长度 ,d表示小数点的位数
小数:float(4,2)表示的范围是-99.99 ~ 99.99,MySQL在保存值时会进行四舍五入
sql
mysql> insert into t4 (id, salary) values (1, 99.99);
mysql> insert into t4 (id, salary) values (1, -99.99);
mysql> insert into t4 (id, salary) values (1, 100); ❌️
mysql> insert into t4 (id, salary) values (1, -100);❌️
mysql> insert into t4 (id, salary) values (1, 99.998);❌️
mysql> insert into t4 (id, salary) values (1, 99.991);
mysql> insert into t4 (id, salary) values (1, 99.994);
mysql> insert into t4 (id, salary) values (1, -99.94);
mysql> insert into t4 (id, salary) values (1, 10.0);
可以看出存99.994会进行四舍五入 去存(前提是四舍五入后也要符合范围,不然插入失败),-99.94同理;存 10.0 会帮我们把精度补齐到两位;
sql
+------+--------+
| id | salary |
+------+--------+
| 1 | 99.99 |
| 1 | -99.99 |
| 1 | 99.99 |
| 1 | 99.99 |
| 1 | 10.00 |
| 1 | -99.94 |
+------+--------+
如果定义的是float(4,2) unsigned 这时,因为把它指定为无符号的数,范围是 【0 ~ 99.99】
sql
mysql> create table tt7(id int, salary float(4,2) unsigned);
mysql> insert into tt7 values(100, -0.1);❌️//直接认为超出有效范围了
mysql> insert into tt7 values(100, -0);✅️
mysql> insert into tt7 values(100, 99.99);✅️
精度损失:
sql
mysql> insert into t5 (id, salary) values (1, 122334455.2);
mysql> insert into t5 (id, salary) values (1, 1223344.1112);
mysql> select *from t5;
+------+-----------+
| id | salary |
+------+-----------+
| 1 | 122334000 |
| 1 | 1223340 |
+------+-----------+
🔥decimal
decimal可以有效的规避精度的损失!
sql
decimal(m, d) [unsigned]
定点数m指定长度,d表示小数点的位数
- decimal(5,2) 表示的范围是 -999.99 ~ 999.99
- decimal(5,2) unsigned 表示的范围 0 ~ 999.99
decimal和float很像,但是有区别;float和decimal表示的精度不一样
sql
mysql> insert into t6 (f1, f2) values (23.12345612, 23.12345612);
mysql> select * from t6;
+-------------+--------------+
| f1 | f2 |
+-------------+--------------+
| 23.12345695 | 23.12345612 |
+-------------+--------------+
发现decimal的精度更准确 ,因此如果我们希望某个数据表示高精度,选择decimal
- float表示的精度大约是7位
decimal整数最大位数m为65。支持小数最大位数d是30。如果d被省略,默认为0,如果m被省略,默认是10
🌏字符串类型
🔥char
char(L): 固定长度字符串 ,L是可以存储的长度,单位为字符,最大长度值可以为255
- 一个中文汉字就是一个字符!
创表:
sql
mysql> create table if not exists t7(
-> id int,
-> name char(2)
-> );
sql
mysql> insert into t7 (id, name) values(11, 'a');
mysql> insert into t7 (id, name) values(11, 'A');
mysql> insert into t7 (id, name) values(11, 'Bb');
mysql> insert into t7 (id, name) values(11, 'Cc');
mysql> insert into t7 (id, name) values(11, 'CcA');❌️
mysql> insert into tt9 values(101, '中国');
mysql> insert into tt9 values(101, '中国人');❌️
+------+------+
| id | name |
+------+------+
| 11 | a |
| 11 | A |
| 11 | Bb |
| 11 | Cc |
| 101| 中国 |
+------+------+
char(2) 表示可以存放两个字符 ,可以是字母或汉字,但是不能超过2个, 最多只能是255
sql
mysql> create table tt10(id int ,name char(256));
ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use BLOB or TEXT instead
🔥varchar
varchar(L): 可变长度字符串 ,L表示字符长度,最大长度65535个字节(不是字符)
举例:
sql
mysql> insert into t8 (id, name) values(123, '中国人能飞!');
mysql> insert into t8 (id, name) values(123, '中国人能飞!!');❌️
+------+--------------------+
| id | name |
+------+--------------------+
| 123 | 中国人能飞! |
+------+--------------------+
sql
mysql> alter table t8 modify name varchar(65535);
ERROR 1074 (42000): Column length too big for column 'name' (max = 21845); use BLOB or TEXT instead
那么char和varchar有什么区别呢??
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字节)。
验证了utf8确实是不能超过21844
sql
mysql> create table tt11(name varchar(21845));❌️
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
mysql> create table tt11(name varchar(21844));
如果该表还有其他字段,可能这个值会更小
🆚char和varchar比较
varchar多申请一个字节来保存该数字大小!

如何选择定长或变长字符串?
- 如果数据确定长度都一样,就使用定长 (
char),比如:身份证,手机号,md5 - 如果数据长度有变化,就使用变长 (
varchar), 比如:名字,地址,但是你要保证最长的能存的进去。 - 定长的磁盘空间比较浪费,但是效率高。
- 变长的磁盘空间比较节省,但是效率低。
- 定长 的意义是,直接开辟好对应的空间
- 把的意义是,在不超过自定义范围的情况下,用多少,开辟多少
🔥日期和时间类型
常用的日期有如下三个:
date:日期'yyyy-mm-dd',占用三字节datetime时间日期格式 'yyyy-mm-dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用八字节timestamp:时间戳 ,从1970年开始的yyyy-mm-dd HH:ii:ss格式和 datetime 完全一致,占用四字节
上手:
sql
mysql> create table if not exists t9(
-> t1 date,
-> t2 datetime,
-> t3 timestamp
-> );
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| t1 | date | YES | | NULL | |
| t2 | datetime | YES | | NULL | |
| t3 | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
对timestamp做插入或者更新, timestamp会自动更新为当前的时间!
我们能插入修改的只有datetime 和 date
- 添加数据时,时间戳自动补上当前时间
- 更新数据,时间戳会更新成当前时间
sql
mysql> insert into t9 (t1, t2) values('1997-7-1','2008-8-8 12:1:1');
mysql> select * from t9;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2026-10-21 10:47:27 |
+------------+---------------------+---------------------+
mysql> update t9 set t1='1999-10-26'; //更新t1时间
mysql> select * from t9;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1999-10-26 | 2008-08-08 12:01:01 | 2026-10-21 10:57:10 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)
🔥enum和set
语法:
sql
enum:枚举,"单选"类型;
enum('选项1','选项2','选项3',...);
该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;而且出于效率考虑,这些值实际存储的是"数字" ,因为这些选项的每个选项值依次对应如下数字:1,2,3,...最多65535个;当我们添加枚举值时,也可以添加对应的数字编号
sql
set:集合,"多选"类型;
set('选项值1','选项值2','选项值3', ...);
该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值;而且出于效率考虑,这些值实际存储的是"数字",因为这些选项的每个选项值依次对应如下数字:1,2,4,8,16,32,...最多64个
案例:
有一个调查表votes,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择(可以多选 ),(男,女)单选
sql
mysql> create table votes(
-> username varchar(30),
-> gender enum('男', '女'),
-> hobby set("代码", "打篮球", "游泳", "足球", "乒乓球")
-> );
+----------+---------------------------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------------------------------------------------+------+-----+---------+-------+
| username | varchar(30) | YES | | NULL | |
| gender | enum('男','女') | YES | | NULL | |
| hobby | set('代码','打篮球','游泳','足球','乒乓球') | YES | | NULL | |
+----------+---------------------------------------------------------+------+-----+---------+-------+
sql
mysql> insert into votes values('张飞', '男', '代码');
mysql> insert into votes values('刘备', '男', '爬山');
mysql> insert into votes values('关羽', '男', '健身');
mysql> insert into votes values('关羽', '未知', '健身'); ❌️
如果爱好选择多个
sql
mysql> insert into votes values('张飞', '男', '代码,游泳');
mysql> select * from votes;
+----------+--------+---------------+
| username | gender | hobby |
+----------+--------+---------------+
| 张飞 | 男 | 代码 |
| 刘备 | 男 | 爬山 |
| 关羽 | 男 | 健身 |
| 张飞 | 男 | 代码,游泳 |
+----------+--------+---------------+
如果是以数字作为插入,这个数字绝对不是对应枚举里的下标 。而是
sql
000001:对应代码
000010:对应打篮球
000011:前两个爱好我们都设置
000100:游泳
...
sql
mysql> insert into votes values('张飞', 1, 0);
mysql> insert into votes values('张飞', 1, 1);
mysql> insert into votes (username) values('卢本伟');
mysql> select * from votes;
+-----------+--------+---------------+
| username | gender | hobby |
+-----------+--------+---------------+
| 张飞 | 男 | |
| 张飞 | 男 | 打篮球 |
| 卢本伟 | NULL | NULL |
+-----------+--------+---------------+
注意NULL 和 '' 不一样!NULL是空,什么都没有,但''是空串!
NULL是我没有建行卡,''是有这张卡,但是里面没钱!
sql
insert into votes values('张飞', 1, 63);
张飞 | 男 | 打篮球,足球,代码,健身,游泳,爬山
也就是把6个比特位全部置1,对应是63
接下来我们对这个表进行查找操作!
先找出所有男的
sql
mysql> select * from votes where gender='男';
+----------+--------+----------------------------------------------+
| username | gender | hobby |
+----------+--------+----------------------------------------------+
| 张飞 | 男 | 代码 |
| 刘备 | 男 | 爬山 |
| 关羽 | 男 | 健身 |
| 张飞 | 男 | 代码,游泳 |
| 张飞 | 男 | |
| 张飞 | 男 | 打篮球 |
| 张飞 | 男 | 打篮球,足球 |
| 张飞 | 男 | 代码 |
| 张飞 | 男 | 打篮球,足球,代码,健身,游泳,爬山 |
+----------+--------+----------------------------------------------+
接下来找出喜欢羽毛球的人
sql
mysql> select * from votes where hobby='代码';
+----------+--------+--------+
| username | gender | hobby |
+----------+--------+--------+
| 张飞 | 男 | 代码 |
| 张飞 | 男 | 代码 |
+----------+--------+--------+
但是这种只能找出只喜欢代码这一个爱好的人,多个爱好(包括代码)的人却找不到!
能找出爱好中有代码的吗?能! 只不过也有缺点,它是严格匹配的!
sql
mysql> select * from votes where hobby='代码,游泳';
+----------+--------+---------------+
| username | gender | hobby |
+----------+--------+---------------+
| 张飞 | 男 | 代码,游泳 |
+----------+--------+---------------+
所以引出了:集合查询使用find_ in_ set函数
sql
find_in_set(sub,str_list)
- 如果 sub 在 str_list 中,则返回下标 ;如果不在,返回0;
str_list用逗号分隔的字符串
sql
mysql> select find_in_set('a', 'a,b,c');
+---------------------------+
| find_in_set('a', 'a,b,c') |
+---------------------------+
| 1 |
+---------------------------+
mysql> select find_in_set('a,c', 'a,b,c');
+-----------------------------+
| find_in_set('a,c', 'a,b,c') |
+-----------------------------+
| 0 |
+-----------------------------+
find_ in_ set只能在一个集合里查找某一个元素是否存在!返回0说明不存在,返回非0则是对应集合的下标!
sql
mysql> select * from votes where find_in_set('游泳', hobby);
+----------+--------+----------------------------------------------+
| username | gender | hobby |
+----------+--------+----------------------------------------------+
| 张飞 | 男 | 代码,游泳 |
| 张飞 | 男 | 打篮球,足球,代码,健身,游泳,爬山 |
+----------+--------+----------------------------------------------+
📢写在最后
接下来登场的是 表的约束!

