🔥个人主页: Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
🌟心向往之行必能至
目录
[1.1 tinyint 类型](#1.1 tinyint 类型)
[1.2 bit类型](#1.2 bit类型)
[1.3 小数类型](#1.3 小数类型)
[1.3.1 float](#1.3.1 float)
[1.3.2 decimal类型](#1.3.2 decimal类型)
[2.1 char类型](#2.1 char类型)
[2.2 varchar](#2.2 varchar)
[2.3 char和varchar对比](#2.3 char和varchar对比)
[2.4 日期和时间](#2.4 日期和时间)
[2.5 enum和set](#2.5 enum和set)
MySQL的数据类型有多种,且有些与C/C++不同,接下来让我们一起学习他们

一.数值类型
| 类型分类 | 数据类型 | 字节数 | 取值范围(有符号) | 取值范围(无符号) | 核心说明 / 使用场景 |
|---|---|---|---|---|---|
| 整数类型 | TINYINT | 1 字节 | -128 ~ 127 | 0 ~ 255 | 迷你整数,适合存储状态值(0/1/2)、性别等少量枚举值 |
| 整数类型 | SMALLINT | 2 字节 | -32768 ~ 32767 | 0 ~ 65535 | 小整数,适合存储少量数据计数(如商品库存、用户积分下限) |
| 整数类型 | MEDIUMINT | 3 字节 | -8388608 ~ 8388607 | 0 ~ 16777215 | 中等整数,适合存储较大计数(如文章阅读量、订单编号前缀) |
| 整数类型 | INT(INTEGER) | 4 字节 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 | 常用整数类型,适合存储大部分常规数值(如用户 ID、商品 ID、订单金额整数部分) |
| 整数类型 | BIGINT | 8 字节 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 | 大整数,适合存储超大数值(如大数据量 ID、时间戳(毫秒级)、海量数据计数) |
| 定点数类型 | DECIMAL(M,D) / DEC(M,D) | 可变(取决于 M) | 取决于 M(总位数)和 D(小数位数) | 取决于 M(总位数)和 D(小数位数) | 高精度小数,适合对精度要求高的场景(如金额、税费、财务数据),无精度丢失 |
| 定点数类型 | NUMERIC(M,D) | 可变(取决于 M) | 与 DECIMAL (M,D) 一致 | 与 DECIMAL (M,D) 一致 | 与 DECIMAL 功能等价,MySQL 中通常作为 DECIMAL 的别名 |
| 浮点数类型 | FLOAT(M,D) | 4 字节 | 单精度浮点,约 ±3.402823466E+38 | 同有符号(浮点数无严格无符号区分,仅数值非负) | 近似值小数,适合对精度要求不高的场景(如身高、体重、温度),可能存在精度丢失 |
| 浮点数类型 | DOUBLE(M,D) | 8 字节 | 双精度浮点,约 ±1.7976931348623157E+308 | 同有符号(浮点数无严格无符号区分,仅数值非负) | 高精度近似小数,适合需要更大取值范围的场景(如科学计算、工程数据),精度高于 FLOAT 但仍有近似误差 |
| 位类型 | BIT(n) | 1~8 字节 | 0 ~ 2ⁿ - 1(n 取值 1~64,默认 1) | 无有符号区分,仅存储二进制位串 | 用于存储二进制数据(如开关状态、权限位掩码),n 表示二进制位数 |

1.1 tinyint 类型
- 数值越界测试:
bash
mysql> insert into test1 values (1,1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test1 values (-125,0);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test1 values (-200,0);
ERROR 1264 (22003): Out of range value for column 'num1' at row 1
mysql> insert into test1 values (0,255);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test1 values (128,256);
ERROR 1264 (22003): Out of range value for column 'num1' at row 1
结果:
bash
mysql> select * from test1;
+------+------+
| num1 | num2 |
+------+------+
| 1 | 1 |
| -125 | 0 |
| 0 | 255 |
+------+------+
3 rows in set (0.00 sec)
说明 :
- 在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的。
- 可以通过UNSIGNED来说明某个字段是无符号的
其他类型自己推导
说明,对于数据,应该灵活选择有符号和无符号,最大化地利用空间
1.2 bit类型
基本语法:
bash
bit[(M)] : 位字段类型。M表示每个值的位数,范围从1到64。如果M被忽略,默认为1
使用:
发现很怪异的现象, a 的数据 10 没有出现
bash
mysql> insert into test2 values(10,10);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test2;
+------+------+
| id | a |
+------+------+
| 10 |
|
+------+------+
1 row in set (0.00 sec)
原因,即需要注意的事项
- bit字段在显示时,是按照ASCII码对应的值显示。 而10的ASCII值不可见
bash
mysql> insert into test2 values(65,65);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test2;
+------+------+
| id | a |
+------+------+
| 10 |
|
| 65 | A |
+------+------+
2 rows in set (0.00 sec)
-
如果我们有这样的值,只存放0或1(用来表示有无或者其他),这时可以定义bit(1)。这样可以节省空间。
bashmysql> create table test3(gender bit(1)); Query OK, 0 rows affected (0.02 sec) mysql> insert test3 value(0),(1); Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert test3 value(2); -----插入二,越界报错 ERROR 1406 (22001): Data too long for column 'gender' at row 11.3 小数类型
1.3.1 float
语法:
bash
float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4个字节
案例:
-
小数:float(4,2)表示的范围是-99.99 ~ 99.99,MySQL在保存值时会进行四舍五入。
bashmysql> create table test4 (id int, salary float(4,2)); Query OK, 0 rows affected (0.01 sec) mysql> insert into test4 values(100,-99.99); Query OK, 1 row affected (0.00 sec) mysql> insert into test4 values(100,-99.991); Query OK, 1 row affected (0.00 sec) mysql> insert into test4 values(100,-99.9911); Query OK, 1 row affected (0.00 sec) mysql> insert into test4 values(100,-999.9); //定义的时候指明了小数要是两位,长度总共是4位, ERROR 1264 (22003): Out of range value for column 'salary' at row 1 mysql> insert into test4 values(100,-99.99); Query OK, 1 row affected (0.00 sec) mysql> insert into test4 values(100,-99.999); // 小数进1.成了100.00 ,会超出4位长度 ERROR 1264 (22003): Out of range value for column 'salary' at row 1 mysql> insert into test4 values(100,-999.9);^C mysql> select * from test4; +------+--------+ | id | salary | +------+--------+ | 100 | -99.99 | | 100 | -99.99 | | 100 | -99.99 | | 100 | -99.99 | +------+--------+ 4 rows in set (0.00 sec)
- 如果定义的是float(4,2) unsigned 这时,因为把它指定为无符号的数,范围是 0 ~ 99.99
bash
mysql> create table test5 (id int ,salary float(4,2)unsigned);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test5 values(100,-1);
ERROR 1264 (22003): Out of range value for column 'salary' at row 1
mysql> insert into test5 values(100,-0);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test5 values(100,99.99);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test5 values(100,100);
ERROR 1264 (22003): Out of range value for column 'salary' at row 1
1.3.2 decimal类型
语法:
bash
decimal(m, d) [unsigned] : 定点数m指定长度,d表示小数点的位数
- decimal(5,2) 表示的范围是 -999.99 ~ 999.99
- decimal(5,2) unsigned 表示的范围 0 ~ 999.99
- decimal和float很像,但是有区别:
- float和decimal表示的精度不一样
验证精度,发现decimal还是原大小,而float已经改变
bash
mysql> create table test6 (id int,salary float(10,8),salarys decimal(10,8));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into test6 values(100,23.12345612,23.12345612);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test6;
+------+-------------+-------------+
| id | salary | salarys |
+------+-------------+-------------+
| 100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
1 row in set (0.00 sec)
| 对比维度 | float(单精度浮点型,扩展含 double 双精度) | decimal(定点小数类型,也作 numeric) |
|---|---|---|
| 数据类型本质 | 二进制浮点型(基于 IEEE 754 标准存储) | 十进制定点型(以字符串形式存储十进制数字,精准记录每一位数值) |
| 存储方式 | 存储二进制近似值,无法精准表示所有十进制小数(如 0.1、0.2) | 存储十进制精确值,按指定的整数位 + 小数位精准存储,无近似误差 |
| 精度特性 | 1. 单精度 float 有效精度约 6-7 位十进制数字;2. 双精度 double 有效精度约 15-17 位十进制数字;3. 存在舍入误差 / 精度丢失,运算后误差可能累积 | 1. 精度可自定义(通常格式为 decimal(p, s),p 为总有效位数,s 为小数位数);2. 无舍入误差,满足高精度数值运算要求;3. 精度上限远高于 float(不同数据库 / 语言中 p 通常支持到 38 位) |
| 主要适用场景 | 1. 对精度要求不高的科学计算、工程模拟;2. 图形图像渲染、大数据量的统计分析(追求运算速度);3. 非金融类的普通数值记录(如身高、体重、温度等) | 1. 金融、财务相关系统(如金额、税费、账户余额、汇率等);2. 需要精准保留小数位的场景(如发票金额、贵金属重量、计量计价等);3. 对数值一致性要求极高的业务运算(如对账、结算) |
| 性能 / 存储开销 | 1. 存储占用小(float 通常 4 字节,double 通常 8 字节);2. 运算速度快(CPU 原生支持二进制浮点运算,效率高);3. 大数据量场景下,内存和计算开销更低 | 1. 存储占用大(随 p 取值增加而增大,通常比 float 占用更多字节);2. 运算速度慢(需额外的十进制运算逻辑,无 CPU 原生优化,效率低于 float);3. 大数据量运算时,内存消耗和耗时更明显 |
| 常见使用限制 | 1. 禁止用于金融场景,精度丢失可能导致账实不符;2. 不宜用于需要精准比较的场景(如 0.1 + 0.2 != 0.3);3. 小数位无法固定精准保留,易出现末尾冗余数字 |
1. 需提前定义精度(p 和 s),超出范围会报错或截断;2. 不适合超大规模科学计算,性能瓶颈明显;3. 部分编程语言 / 数据库中,运算语法略复杂(需显式转换类型) |
二.字符串类型
2.1 char类型
语法:
bash
char(L): 固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255
使用:
bash
mysql> create table test7(id int,name char(2));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into test7 values(100,'中');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test7 values(100,'中国');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test7 values(100,'中国人');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql> select * from test7;
+------+--------+
| id | name |
+------+--------+
| 100 | 中 |
| 100 | 中国 |
+------+--------+
2 rows in set (0.00 sec)
我们发现,之前我们在学C/C++的时候,说过一个中文字符占两个字符,但这里似乎一个中文字符也是占一个字符,其实是在 UTF-8 字符集下,一个汉字占 3 个字节,但 char(2) 是按字符数计数,所以 1 个汉字满足要求。
说明:
char(2)表示可以存放两个字符,可以是字母/汉字,但是不能超过两个,最大只能是255
验证成功
bash
mysql> create table test8(id int,name char(256));
ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use BLOB or TEXT instead
2.2 varchar
语法:
bash
varchar(L): 可变长度字符串,L表示字符长度,最大长度65535个字节
使用:
bash
mysql> create table test8(id int,name varchar(6)); ----最多可以存6个字符
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test8 values(100,'hello');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test8 values(100,'我爱你,中国');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test8 values(100,'我爱你,中国人');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql> selcet * from test8;
mysql> select * from test8;
+------+------------------+
| id | name |
+------+------------------+
| 100 | hello |
| 100 | 我爱你,中国 |
+------+------------------+
说明:
- 关于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个字符
bash
mysql> create table test9(ame varchar(21845))charset=utf8 ;
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 test9(ame varchar(21844))charset=utf8 ;
Query OK, 0 rows affected (0.01 sec)
2.3 char和varchar对比
| 实际存储 | char(4) | varchar(4) | char 占用字节 | varchar 占用字节 |
|---|---|---|---|---|
| abcd | abcd | abcd | 4*3=12 | 4*3+1=13 |
| A | A | A | 4*3=12 | 1*3+1=4 |
| Abcde | × | × | 数据超过长度 | 数据超过长度 |
如何选择定长或变长字符串?
-
如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5
-
如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去。
-
定长的磁盘空间比较浪费,但是效率高。
-
变长的磁盘空间比较节省,但是效率低。
-
定长的意义是,直接开辟好对应的空间
-
变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。
场景 推荐类型 例子 长度固定的短文本 char 手机号、性别、邮编 长度变化较大的文本 varchar 用户名、商品描述、个人简介 需要频繁更新且长度稳定的数据 char 状态码、类型标识 存储大量长度不一的字符串 varchar 文章标题、用户留言
2.4 日期和时间
常用的日期有如下三个:
- date :日期 'yyyy-mm-dd' ,占用三字节
- datetime 时间日期格式 'yyyy-mm-dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用八字节
- timestamp :时间戳,从1970年开始的 yyyy-mm-dd HH:ii:ss 格式和 datetime 完全一致,占用四字节
使用
更新数据 update 表名 set 表格首行名称 =XXX;
bash
mysql> create table birthday(t1 date,t2 datetime,t3 timestamp);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1');--插入两
种时间
Query OK, 1 row affected (0.00 sec)
mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2026-01-15 11:07:18 |--添加数据时,时间戳自动补
上当前时间
+------------+---------------------+---------------------+
1 row in set (0.00 sec)
mysql> update birthday set t1='2000-1-01';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2026-01-15 11:08:39 |-- 更新数据,时间戳会更新
成当前时间
+------------+---------------------+---------------------+
1 row in set (0.00 sec)
查看birthday,发现也说明了timestamp不能位空,且有缺省值和补充值
bash
mysql> desc birthday;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| t1 | date | YES | | NULL | |
| t2 | datetime | YES | | NULL | |
| t3 | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP
| 特性 | date |
datetime |
timestamp |
|---|---|---|---|
| 格式 | yyyy-mm-dd |
yyyy-mm-dd HH:ii:ss |
yyyy-mm-dd HH:ii:ss |
| 存储范围 | 1000-01-01 ~ 9999-12-31 |
1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
1970-01-01 00:00:01 ~ 2038-01-19 03:14:07 |
| 占用空间 | 3 字节 | 8 字节 | 4 字节 |
| 时区影响 | 无 | 无 | 受时区影响,存储和读取时会转换 |
| 自动更新 | 不支持 | 不支持 | 支持,可设置为插入 / 更新时自动记录当前时间 |
| 适用场景 | 仅需存储日期,如生日、注册日期 | 需要存储完整日期 + 时间,且范围大,如订单创建时间 | 需记录操作时间、且对空间敏感,如数据更新时间/评论等 |
2.5 enum和set
- enum
语法:
bash
enum:枚举,"单选"类型;
enum('选项1','选项2','选项3',...);
该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;而且出于效率考虑,这些值实际存储的是" 数字 " ,因为这些选项的每个选项值依次对应如下数字: 1,2,3,.... 最多 65535个;当我们添加枚举值时,也可以添加对应的数字编号。
使用:
-
set
bashset:集合,"多选"类型; set('选项值1','选项值2','选项值3', ...);该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值;而且出于效率考虑,这些值实际存储的是" 数字 " ,因为这些选项的每个选项值依次对应如下数字: 1,2,4,8,16,32 , .... 最多64 个。
说明:不建议在添加枚举值,集合值的时候采用数字的方式,因为不利于阅读。
使用:
有一个调查表 ,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择 ( 可以多选 ) ,
(男,女) [ 单选 ]
创建表格
bash
mysql> create table person(
-> username varchar(30),
-> hobby set('登山','游泳','篮球','武术'),--注意:使用数字标识每个爱好的时候,想想
Linux权限,采用比特位位置来个set中的爱好对应起来
-> gender enum('男','女')--注意:使用数字标识的时候,就是正常的数组下标
-> );
Query OK, 0 rows affected (0.01 sec)
插入数据:
bash
mysql> insert into person values('张三','登山,武术','男');
Query OK, 1 row affected (0.00 sec)
mysql> insert into person values('A','登山,武术',0);
ERROR 1265 (01000): Data truncated for column 'gender' at row 1
mysql> insert into person values('A','登山,武术','0');
Query OK, 1 row affected (0.00 sec)
mysql> insert into person values('A','0','1');
Query OK, 1 row affected (0.00 sec)
mysql> insert into person values('A','1','1');
Query OK, 1 row affected (0.00 sec)
mysql> insert into person values('A','5','1');
Query OK, 1 row affected (0.00 sec)
查询结果
我们发现enum使用枚举值可以成功设置,也set也可以通过使用比特位设置 1--->0001 所以登山
5-----> 0101 所以登山 游泳
bash
mysql> select * from person;
+----------+---------------+--------+
| username | hobby | gender |
+----------+---------------+--------+
| 张三 | 登山,武术 | 男 |
| A | 登山,武术 | |
| A | | 男 |
| A | 登山 | 男 |
| A | 登山,篮球 | 男 |
+----------+---------------+--------+
5 rows in set (0.00 sec)
查找所有喜欢登山的人:
bash
mysql> select * from person where hobby='登山';
+----------+--------+--------+
| username | hobby | gender |
+----------+--------+--------+
| A | 登山 | 男 |
+----------+--------+--------+
1 row in set (0.00 sec)
但发现只能查找兴趣只为登山的,这显然不是我想要的
- 集合查询使用find_ in_ set函数
find_in_set(sub,str_list) :如果 sub 在 str_list 中,则返回下标;如果不在,返回 0 ;
str_list 用逗号分隔的字符串。
前置使用
bash
mysql> select find_in_set('a','a,b,c');
+--------------------------+
| find_in_set('a','a,b,c') |
+--------------------------+
| 1 |
+--------------------------+
1 row in set (0.00 sec)
mysql> select find_in_set('d','a,b,c');
+--------------------------+
| find_in_set('d','a,b,c') |
+--------------------------+
| 0 |
+--------------------------+
1 row in set (0.00 sec)
实战查找:
bash
mysql> select * from person where find_in_set('登山',hobby);
+----------+---------------+--------+
| username | hobby | gender |
+----------+---------------+--------+
| 张三 | 登山,武术 | 男 |
| A | 登山,武术 | |
| A | 登山 | 男 |
| A | 登山,篮球 | 男 |
+----------+---------------+--------+
4 rows in set (0.00 sec)
| 对比维度 | enum 类型 |
set 类型 |
|---|---|---|
| 可选值数量限制 | 只能选择 1 个 预定义值(必须选 1 个,除非设置为允许 NULL) | 可以选择 0 个、1 个或多个 预定义值(多选时用逗号分隔) |
| 最大可选值数量 | 最多支持 65535 个 预定义选项 | 最多支持 64 个 预定义选项 |
| 存储原理 | 以整数索引存储(底层对应数字序号,如第一个选项对应 1,第二个对应 2),占用 1~2 字节(根据选项数量而定) | 以整数位掩码存储(每个选项对应一个二进制位),占用 1~8 字节(根据选项数量而定) |
| 插入数据格式 | 只能传入单个预定义选项字符串,如 '男'、'女' |
多选时需将多个选项放入同一个字符串,用英文逗号分隔,如 '登山,游泳,篮球' |
| 重复值处理 | 无重复场景(仅单选),无需处理重复 | 自动去重,即使插入重复选项(如 '登山,登山,游泳'),存储后仍为 '登山,游泳' |
| 适用场景 | 单选场景,无多种结果并存的需求 | 多选场景,支持多种结果并存的需求 |
| 示例场景 | 性别(男 / 女)、订单状态(待支付 / 已支付 / 已取消)、用户类型(普通用户 / VIP 用户) | 兴趣爱好(登山 / 游泳 / 篮球)、商品标签(热销 / 新品 / 包邮)、权限列表(查看 / 编辑 / 删除) |
| 插入合法示例 | insert into person values('李四','游泳','女') |
insert into person values('张三','登山,篮球','男') |
| 插入非法示例 | insert into person values('王五','游泳','男,女')(多选性别) |
insert into person values('赵六','跑步','男')(插入预定义外的选项) |
