MySQL数据类型全解析

上一篇学了简单的操作,现在我们再来认识一下MySQL数据类型.

目录

[(一) MySQL的数据类型](#(一) MySQL的数据类型)

[1. 数据类型分类](#1. 数据类型分类)

2.数值类型

[2.1 tinyint类型](#2.1 tinyint类型)

[2.2 BIT 类型](#2.2 BIT 类型)

[3. 小数类型](#3. 小数类型)

[3.1 float 类型](#3.1 float 类型)

[3.2 decimal 类型(高精度定点数)](#3.2 decimal 类型(高精度定点数))

[核心区别:FLOAT 与 DECIMAL 精度对比](#核心区别:FLOAT 与 DECIMAL 精度对比)

[4. 字符串类型](#4. 字符串类型)

[4.1 char 固定长度字符串](#4.1 char 固定长度字符串)

[4.2 VARCHAR 可变长度字符串](#4.2 VARCHAR 可变长度字符串)

使用示例

[4.3 CHAR 与 VARCHAR 对比与选择](#4.3 CHAR 与 VARCHAR 对比与选择)

[5. 日期和时间类型](#5. 日期和时间类型)

[6. enum 和 set 类型(字符串约束类型)](#6. enum 和 set 类型(字符串约束类型))

[1. ENUM 枚举(单选类型)](#1. ENUM 枚举(单选类型))

[2. SET 集合(多选类型)](#2. SET 集合(多选类型))

[3. find_in_set 函数说明](#3. find_in_set 函数说明)


(一) MySQL的数据类型

1. 数据类型分类

我们先来简单看看大概分类

大致解读:这张表是MySQL 数据类型的分类速查表 ,按存储类别划分,核心作用是快速查阅各类数据的定义规则、存储特性与适用场景,整体分为 4 大类别:

  1. 数值类型:涵盖整数(BIT、TINYINT、INT 等)、浮点数 / 定点数(FLOAT、DECIMAL 等),明确标注了各类型的位数、是否带符号、精度及存储规则,是定义数字字段(如 ID、数量、金额)的核心参考。
  2. 文本、二进制类型:包含字符串(CHAR、VARCHAR)、大文本 / 二进制数据(TEXT、BLOB),区分了固定长度与可变长度字符串,同时说明 TEXT/BLOB 的特殊限制(如不支持全文索引)。
  3. 时间日期类型:聚焦 DATE、DATETIME、TIMESTAMP,直接标注格式(yyyy-mm-dd、yyyy-mm-dd hh:mm:ss)与时间戳特性,明确时间类字段的存储形式。
  4. String 类型:为字符串扩展类型,ENUM(枚举,单选预设值)、SET(集合,多选预设值),用于限制字段的合法取值范围,规范数据录入。

2.数值类型

大致解读:这张表是MySQL 整数类型的精准参数表,聚焦整数类型的核心硬件与范围特性

2.1 tinyint类型

(1)默认有符号 TINYINT 测试

在 MySQL 中,整型默认是有符号的 ,TINYINT 有符号的取值范围为:-128 ~ 127

先创建一个表:(注意一定要先进入库中,如 use mqlearn)

复制代码
create table if not exists t1( num tinyint);

先插入一个合理的数据

复制代码
insert into t1 values(1);

//运行结果:
Query OK, 1 row affected (0.00 sec)

可知合法的

试试插入一个超出范围的:如128

复制代码
insert into t1 values(128);

//运行结果:
ERROR 1264 (22003): Out of range value for column 'num' at row 1

可知直接报错了

我们来看看表中数据:

(2)无符号 TINYINT(UNSIGNED)测试

通过 UNSIGNED 关键字可将字段设置为无符号类型 ,仅允许存储非负数,TINYINT UNSIGNED 取值范围为:0 ~ 255

在创建一个表:

复制代码
create table if not exists t2( num tinyint unsigned);

插入一个负数 -1

复制代码
insert into t2 values(-1);

//运行结果:
ERROR 1264 (22003): Out of range value for column 'num' at row 1

可知超出范围报错

再试试插入最大值 255

复制代码
insert into t2 values(255);

//运行结果:
Query OK, 1 row affected (0.00 sec)

可知插入成功

查看表中数据:

推导与规范说明

  1. 在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的。可以通过UNSIGNED来说明某个字段是无符号的
  2. 其他整型(SMALLINT/INT/BIGINT)的有符号 / 无符号规则与 TINYINT 完全一致,仅取值范围不同,可按此逻辑自行推导。
  3. 开发规范建议 :尽量不要使用 UNSIGNED 无符号类型。对于 INT 类型存不下的数据,INT UNSIGNED 通常也无法安全存储,直接将字段类型升级为 BIGINT 是更稳妥、更通用的设计方案

2.2 BIT 类型

(1)基本语法

复制代码
BIT[(M)]:位字段类型,用于存储二进制位数据

解释:

  • M :表示每个值的位数 ,取值范围:1 ~ 64
  • 省略 M 时,默认值为 1

(2)基础使用示例

先创建一个表

复制代码
create table if not exists t3( id int, a bit(8) );

紧接着插入(10,10)

复制代码
insert into t3 values(10,10);

运行结果:

解释:

BIT(M) 是二进制位类型,专门用来存储二进制数据,BIT(8) 就是 1 字节(8 个二进制位)的存储空间。

插入的 10 是十进制整数,MySQL 会把它自动转为二进制 1010,补全 8 位就是 00001010,再转为十六进制就是 0x0A。而有些伙伴会出现空白也是正常的------出现空白的情况,本质是客户端 / 版本差异 + 不可见字符的显示问题。

再看看输入(65,65)

BIT 字段在查询显示时,会自动按照 ASCII 码 对应字符展示,而非直接显示数字

复制代码
insert into t3 values (65,65);

再看一下表中

该现象也是正常,有些65右边可能得到A,现象解释:

插入 65,对应 ASCII 码就是字母 A。新版 MySQL 命令行默认把 bit 类型以 十六进制(0x41) 显示。

把 bit 类型以 ** 字符(A)** 显示。可以使用 CHAR(a) 函数可以强制显示为字符

复制代码
select id, cast(a as char) as a from t3;

运行结果:

(3)BIT 类型最佳使用场景

当字段仅需存储 0 或 1 (如布尔状态、性别开关)时,使用 BIT(1) 可极大节省存储空间。

在创建一个表

复制代码
create table if not exists t4( gender bit(1) );

插入结果:

复制代码
//插入 0,成功
mysql> insert into t4 values(0);
Query OK, 1 row affected (0.01 sec)

//插入 1,成功
mysql> insert into t4 values(1);
Query OK, 1 row affected (0.01 sec)

//插入失败,2已经越界了
mysql> insert into t4 values(2);
ERROR 1406 (22001): Data too long for column 'gender' at row 1

总结

  1. BIT(M) 用于存储二进制位,M 范围 1~64,默认 1
  2. 查询时按 ASCII 码显示字符,不会直接显示数字(按照不同版本来的)
  3. 最适合存储 0/1 二值状态,空间利用率最高

3. 小数类型

3.1 float 类型

语法

复制代码
FLOAT[(M, D)] [UNSIGNED]

解释:

  • M:总有效数字长度(整数位 + 小数位)
  • D:小数点后的位数
  • 占用 4 字节 存储空间
  • 存储时会自动四舍五入

案例 1:有符号 FLOAT

FLOAT(4,2) 表示:总共 4 位数字,其中小数占 2 位取值范围-99.99 ~ 99.99

创建表

复制代码
create table if not exists t6( id int, salary float(4,2) );

插入:

复制代码
-- 插入合法最小值
mysql> insert into tt6 values(100, -99.99);

-- 插入超界小数,多出来会怎么样?
mysql> insert into tt6 values(101, -99.991);

-- 插入正常值89.992,多出来会怎么样?
mysql> insert into t6 values(102, 89.992);
Query OK, 1 row affected (0.00 sec)

-- 插入正常值89.999,多出来会怎么样?
mysql> insert into t6 values(103, 89.999);
Query OK, 1 row affected (0.00 sec)

查询结果

发现多出的部分------MySQL在保存值时会进行四舍五入。

故也可知范围推导FLOAT(6,3) 取值范围:-999.999 ~ 999.999

案例 2:无符号 FLOAT

FLOAT(4,2) UNSIGNED取值范围0 ~ 99.99(不允许负数)

创建表

复制代码
create table if not exists t6( id int, salary float(4,2) unsigned);

插入

复制代码
-- 插入负数,报越界警告
mysql> insert into tt7 values(100, -0.1);
ERROR 1146 (42S02): Table 'mqlearn.tt7' doesn't exist

查看警告

mysql> show warnings;

再插入几个合法值:

复制代码
mysql> insert into t7 values(101,98.992);
ERROR 1146 (42S02): Table 'mqlearn.tt7' doesn't exist
mysql> insert into t7 values(101,98.992);
Query OK, 1 row affected (0.00 sec)

查看表格:

发现还是四舍五入的。

3.2 decimal 类型(高精度定点数)

语法

复制代码
DECIMAL(M, D) [UNSIGNED]

解释:

  • M:总有效位数(最大 65)
  • D:小数位数(最大 30)
  • 省略 D 时默认 0 ,省略 M 时默认 10
  • 精度绝对准确,无精度丢失

取值示例

  • DECIMAL(5,2)-999.99 ~ 999.99
  • DECIMAL(5,2) UNSIGNED0 ~ 999.99

核心区别:FLOAT 与 DECIMAL 精度对比

FLOAT 精度有限(约 7 位有效数字),会出现精度丢失;DECIMAL 为高精度定点数,完全精准。

创建表:

复制代码
create table if not exists t8( id int, salary float(10,8), salary2 decimal(10,8) );

-- 插入相同数据
mysql> insert into t8 values(100, 23.12345612, 23.12345612);
Query OK, 1 row affected (0.00 sec)

查询对比:

结论:FLOAT 出现精度误差,DECIMAL 完全保留原始数据。

总结

  1. FLOAT:精度有限,适合普通小数(如温度、身高)
  2. DECIMAL :精度绝对准确,适合金额、价格、财务数据
  3. 高精度场景必须使用 DECIMAL,禁止用 FLOAT/DOUBLE

4. 字符串类型

4.1 char 固定长度字符串

语法

复制代码
CHAR(L)

解释:

  • 固定长度字符串类型
  • L 表示最多可存储的字符个数,字母、汉字均按 1 个字符计算
  • 最大长度 255 个字符

使用示例

创建表,name 字段最多存放 2 个字符

复制代码
create table if not exists t9( id int, name char(2) );

插入

复制代码
-- 插入字母
mysql> insert into t9 values(100, 'ab');
Query OK, 1 row affected (0.01 sec)
-- 插入汉字
mysql> insert into t9 values(100, '你好');
Query OK, 1 row affected (0.00 sec)

查询结果:

结果可知,

CHAR (L) 的长度单位是字符,而非字节:无论英文字母、数字还是汉字,每个字符都按 1 个单位计算 ,因此 CHAR(2) 既能存 2 个字母,也能存 2 个汉字;该规则同样适用于 VARCHAR (L)

长度限制

CHAR(L) 中 L 最大只能为 255,超过会直接报错:

复制代码
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

4.2 VARCHAR 可变长度字符串

语法

复制代码
VARCHAR(L)

解释:

  • 可变长度字符串类型
  • L 表示最多可存储的字符个数
  • 理论最大长度受限于 65535 字节 ,但需预留 1~3 字节存储数据长度,因此有效最大字节为 65532

使用示例

创建表,name 最多存放 6 个字符

复制代码
create table if not exists t10( id int, name varchar(6) );

插入

复制代码
-- 插入数据
mysql> insert into t10 values (100,'hello');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t10 values(101,'我爱你,中国');
Query OK, 1 row affected (0.00 sec)

mysql> isnert into t10 (102,'我爱你,中国!');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'isnert into t10 (102,'我爱你,中国!')' at line 1

查询结果:

可知,标点符号也算一个字符。

最大字符数与字符集的关系

VARCHAR 的最大可设长度 L 与字符集有关:

  • UTF8 编码:1 字符 ≈ 3 字节 → 最大 L ≈ 65532 / 3 = 21844

  • GBK 编码:1 字符 ≈ 2 字节 → 最大 L ≈ 65532 / 2 = 32766

    -- 超过 21844 报错
    mysql> create table if not exists t11(name 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

    -- 21844 可正常创建
    mysql> create table if not exists t11(name varchar(21844)) charset=utf8;
    Query OK, 0 rows affected, 1 warning (0.01 sec)

4.3 CHAR 与 VARCHAR 对比与选择

核心区别

  • CHAR:固定长度,创建时直接开辟固定空间
  • VARCHAR:可变长度,按实际数据占用空间

优缺点

  • CHAR:空间较浪费,但访问效率高
  • VARCHAR:空间更节省,但效率略低

如何选择

  • 长度基本固定的字段:优先用 CHAR例:身份证号、手机号、MD5 串、性别编码等
  • 长度波动较大的字段:优先用 VARCHAR例:用户名、昵称、地址、标题、备注等

5. 日期和时间类型

MySQL 提供了多种时间存储类型,常用的有 DATE、DATETIME、TIMESTAMP 三种。

基本介绍

  • DATE

    • 格式:yyyy-MM-dd(仅日期)
    • 占用:3 字节
    • 范围:1000-01-01 ~ 9999-12-31
  • DATETIME

    • 格式:yyyy-MM-dd HH:mm:ss(日期 + 时间)
    • 占用:8 字节
    • 范围:1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
  • TIMESTAMP

    • 格式:yyyy-MM-dd HH:mm:ss(与 DATETIME 显示一致)
    • 占用:4 字节
    • 特点:自动更新,插入 / 更新数据时会自动填充为当前系统时间

案例演示

创建表格

复制代码
create table if not exists birthday(t1 date, t2 datetime, t3 timestamp);

需要注意:

在创建 birthday 表时,t3 字段使用 TIMESTAMP 类型并设置 DEFAULT CURRENT_TIMESTAMP。在 MySQL 8.0 版本中,该设置仅表示插入数据时自动填充当前时间 ,执行 UPDATE 修改其他字段时,t3 不会自动更新。

而低版本 MySQL(如 5.x)中,TIMESTAMP 字段默认自带 ON UPDATE CURRENT_TIMESTAMP 属性,修改数据时会自动刷新时间。因此想要在 MySQL 8.0 中实现更新时自动修改 t3,需要显式添加 ON UPDATE CURRENT_TIMESTAMP

完整指令:

复制代码
drop table birthday;
create table birthday(
    t1 date,
    t2 datetime,
    t3 timestamp DEFAULT CURRENT_TIMESTAMP  -- 这里加了自动填充
);

插入

复制代码
-- 插入数据(只给 t1、t2 赋值,t3 自动生成当前时间)
mysql> insert into birthday(t1,t2) values('2007-1-25', '2006-11-22 12:25:28');
Query OK, 1 row affected (0.00 sec)

查询:

更新数据:

复制代码
mysql> update birthday set t1='2007-1-26';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

查看结果;

从结果可知:**TIMESTAMP 类型在插入数据时会自动填充当前系统时间,更新该行任意字段时,又会自动刷新为最新时间,**这是它和 DATE、DATETIME 最明显的区别,后两者不会自动赋值或自动更新。


6. enum 和 set 类型(字符串约束类型)

这两个类型都可以提前定义可选值,限制字段只能输入预设内容。

1. ENUM 枚举(单选类型)

  • 语法:ENUM('选项1','选项2','选项3', ...)
  • 特点:只能选一个值
  • 底层:用数字 1、2、3...... 对应存储,最多 65535 个选项
  • 插入时可以用字符串 ,也可以用数字

2. SET 集合(多选类型)

  • 语法:SET('选项1','选项2','选项3', ...)
  • 特点:可以选 0 个、1 个或多个值
  • 底层:用二进制位(1、2、4、8......)存储,最多 64 个选项
  • 多个值之间用英文逗号分隔

案例演示

创建表

复制代码
create table if not exists votes(
    username varchar(30),
    hobby set('登山','游泳','篮球','武术'),
    gender enum('男','女')
);

插入测试数据

复制代码
-- 只选登山
mysql> insert into votes values('LiLei', '登山', '男');
Query OK, 1 row affected (0.00 sec)

-- 登山+武术+游泳
mysql> insert into votes values('雷锋', '登山,武术,游泳', '男');
Query OK, 1 row affected (0.00 sec)

-- 全部爱好都选
mysql> insert into votes values('Juse', '登山,游泳,篮球,武术', '女');
Query OK, 1 row affected (0.00 sec)

-- 不选登山,用于对比
mysql> insert into votes values('HanMeiMei', '游泳,篮球', '女');
Query OK, 1 row affected (0.00 sec)

直接使用等值匹配(错误查询)

复制代码
select * from votes where hobby='登山';

现象:

由现象可知 :只查出了只选了登山的用户,同时选了多个爱好(登山 + 武术 + 游泳、全部爱好)的用户都没有出现。

用 find_in_set 函数查询(正确查询)

复制代码
select * from votes where find_in_set('登山', hobby);

现象:

现象知道 :所有包含登山的记录都被查询出来,无论只选一个,还是多选、全选。

3. find_in_set 函数说明

语法:

复制代码
find_in_set(sub, str_list)

解释

  • 功能:在以逗号分隔的字符串 str_list 中查找 sub
  • 返回结果:存在则返回位置下标,不存在则返回 0

示例:

复制代码
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)

本文介绍了MySQL的数据类型,大家后续有补充或发现疏漏、错误,欢迎在评论区一起交流探讨~感谢各位的阅读!

相关推荐
Harvy_没救了2 小时前
MySQL主从架构深度解析:原理、优化与实践指南
运维·mysql·架构
XDHCOM2 小时前
NoSQL查询语言问世,CouchDB与SQLite联手革新数据库交互方式,让数据操作更高效
数据库·nosql·couchdb
黑牛儿2 小时前
MySQL 实战进阶:从单表优化到分布式数据库适配
数据库·分布式·mysql
momin~2 小时前
MySQL-part3【数据库约束、表设计】
数据库·mysql
todoitbo2 小时前
时序数据库选型指南:从大数据场景出发
大数据·数据库·时序数据库
芯盾时代2 小时前
政务行业面临的网络风险
网络·数据库·网络安全
fire-flyer2 小时前
第 3 篇:ClickHouse 表结构设计的核心原则
大数据·数据库·clickhouse
FinTech老王2 小时前
时序数据库存储引擎解密:LSM-Tree vs B-Tree vs 倒排索引,谁最适合时序场景?
数据库·时序数据库·lsm-tree
阿坤带你走近大数据2 小时前
存储过程在 oracle数据库管理工具里定时自动化运行方案
数据库·oracle·自动化