MySQL数据类型

MySQL 数据类型详解(含实战案例)

本文系统讲解 MySQL 中常用的数据类型,包括数值类型、字符串类型、日期时间类型、枚举与集合类型,附带可直接运行的 SQL 示例。


一、数据类型分类

MySQL 中的数据类型主要分为以下几类:

  • 数值类型tinyintintfloatdecimalbit
  • 字符串类型charvarchartextblob
  • 日期和时间类型datedatetimetimestamp
  • 枚举和集合类型enumset

二、数值类型

2.1 tinyint 类型

tinyint 占 1 个字节,默认是有符号的,范围为 -128 ~ 127

数值越界测试:

sql 复制代码
-- 创建表
mysql> create table tt1(num tinyint);
Query OK, 0 rows affected (0.02 sec)

-- 正常插入
mysql> insert into tt1 values(1);
Query OK, 1 row affected (0.00 sec)

-- 越界插入,报错
mysql> insert into tt1 values(128);
ERROR 1264 (22003): Out of range value for column 'num' at row 1

说明: 在 MySQL 中,整型默认是有符号的。可以通过 UNSIGNED 来声明无符号字段。

无符号案例:

sql 复制代码
-- 创建无符号 tinyint 表
mysql> create table tt2(num tinyint unsigned);

-- 无符号范围是 0 ~ 255,插入 -1 报错
mysql> insert into tt2 values(-1);
ERROR 1264 (22003): Out of range value for column 'num' at row 1

-- 正常插入 255
mysql> insert into tt2 values(255);
Query OK, 1 row affected (0.02 sec)

建议: 尽量不使用 unsigned。对于 int 类型可能存放不下的数据,int unsigned 同样可能存放不下,不如直接将 int 提升为 bigint

2.2 bit 类型

基本语法:

复制代码
bit[(M)] : 位字段类型。M 表示每个值的位数,范围从 1 到 64。如果 M 被忽略,默认为 1。

举例:

sql 复制代码
mysql> create table tt4 (id int, a bit(8));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt4 values(10, 10);
Query OK, 1 row affected (0.01 sec)

-- bit 字段显示时按 ASCII 码对应值显示,10 没有对应可显示字符
mysql> select * from tt4;
+------+------+
| id   | a    |
+------+------+
|   10 |      |
+------+------+

mysql> insert into tt4 values(65, 65);

mysql> select * from tt4;
+------+------+
| id   | a    |
+------+------+
|   10 |      |
|   65 | A    |  -- 65 对应 ASCII 字符 'A'
+------+------+

使用场景: 如果字段只存放 01,可以定义 bit(1) 来节省空间。

sql 复制代码
mysql> create table tt5(gender bit(1));
mysql> insert into tt5 values(0);
mysql> insert into tt5 values(1);
mysql> insert into tt5 values(2); -- 越界
ERROR 1406 (22001): Data too long for column 'gender' at row 1

2.3 小数类型

2.3.1 float

语法:

复制代码
float[(m, d)] [unsigned] : M 指定显示长度,d 指定小数位数,占用空间 4 个字节

float(4,2) 表示的范围是 -99.99 ~ 99.99,MySQL 在保存值时会进行四舍五入。

sql 复制代码
mysql> create table tt6(id int, salary float(4,2));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt6 values(100, -99.99);
Query OK, 1 row affected (0.00 sec)

-- 多出的小数位被四舍五入截断
mysql> insert into tt6 values(101, -99.991);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt6;
+------+--------+
| id   | salary |
+------+--------+
|  100 | -99.99 |
|  101 | -99.99 |
+------+--------+

无符号 float:

如果定义 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); -- 贊界,会产生 warning
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into tt7 values(100, 99.99);
Query OK, 1 row affected (0.00 sec)
2.3.2 decimal

语法:

复制代码
decimal(m, d) [unsigned] : 定点数,m 指定长度,d 表示小数点的位数

decimal(5,2) 表示的范围是 -999.99 ~ 999.99decimal 整数最大位数 m 为 65,支持小数最大位数 d 是 30。

float 与 decimal 精度对比:

sql 复制代码
mysql> create table tt8(id int, salary float(10,8), salary2 decimal(10,8));

mysql> insert into tt8 values(100, 23.12345612, 23.12345612);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt8;
+------+-------------+-------------+
| id   | salary      | salary2     |
+------+-------------+-------------+
|  100 | 23.12345695 | 23.12345612 |  -- decimal 精度更准确
+------+-------------+-------------+

建议: 如果希望小数的精度高,推荐使用 decimal


三、字符串类型

3.1 char

语法:

复制代码
char(L): 固定长度字符串,L 是可以存储的长度,单位为字符,最大长度值可以为 255
sql 复制代码
mysql> create table tt9(id int, name char(2));

mysql> insert into tt9 values(100, 'ab');
Query OK, 1 row affected (0.00 sec)

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

mysql> select * from tt9;
+------+--------+
| id   | name   |
+------+--------+
|  100 | ab     |
|  101 | 中国   |
+------+--------+

-- 超过 2 个字符报错
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

3.2 varchar

语法:

复制代码
varchar(L): 可变长度字符串,L 表示字符长度,最大长度 65535 个字节

关于 varchar(L) 中 L 的实际最大值,与表的编码密切相关:

编码 每字符字节数 varchar 最大字符数
utf8 3 65532 / 3 = 21844
gbk 2 65532 / 2 = 32766

有 1~3 个字节用于记录数据大小,所以有效字节数是 65532。

sql 复制代码
mysql> create table tt10(id int, name varchar(6)); -- 可存放 6 个字符

mysql> insert into tt10 values(100, 'hello');
mysql> insert into tt10 values(100, '我爱你,中国');

mysql> select * from tt10;
+------+--------------------+
| id   | name               |
+------+--------------------+
|  100 | hello              |
|  100 | 我爱你,中国       |
+------+--------------------+

3.3 char 和 varchar 的选择

场景 推荐类型
长度固定的数据(身份证、手机号、md5) char
长度可变的数据(名字、地址) varchar

核心区别:

  • 定长(char):磁盘空间比较浪费,但效率高(直接开辟好对应空间)
  • 变长(varchar):磁盘空间比较节省,但效率低(用多少,开辟多少)

四、日期和时间类型

类型 格式 范围 字节数
date yyyy-MM-dd --- 3 字节
datetime yyyy-MM-dd HH:mm:ss 1000 ~ 9999 8 字节
timestamp yyyy-MM-dd HH:mm:ss 1970 年起 4 字节

案例:

sql 复制代码
-- 创建表
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
Query OK, 0 rows affected (0.01 sec)

-- 插入数据,timestamp 会自动填充当前时间
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 | 2017-11-12 18:28:55 | -- timestamp 自动填充
+------------+---------------------+---------------------+

-- 更新数据时,timestamp 会自动更新为当前时间
mysql> update birthday set t1='2000-1-1';
Query OK, 1 row affected (0.00 sec)

mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2017-11-12 18:32:09 | -- 自动更新
+------------+---------------------+---------------------+

五、enum 和 set 类型

5.1 enum(枚举 --- 单选)

语法:

sql 复制代码
enum('选项1','选项2','选项3',...);

最终一个单元格中只存储其中一个值。出于效率考虑,这些值实际存储的是数字(1, 2, 3, ...),最多支持 65535 个选项。

5.2 set(集合 --- 多选)

语法:

sql 复制代码
set('选项值1','选项值2','选项值3', ...);

一个单元格中可存储其中任意多个值。存储时使用位图(1, 2, 4, 8, 16, 32, ...),最多支持 64 个选项。

不建议在添加枚举值和集合值时使用数字方式,因为不利于阅读。

5.3 综合案例

创建调查表:

sql 复制代码
mysql> create table votes(
    -> username varchar(30),
    -> hobby set('登山','游泳','篮球','武术'),  -- 多选
    -> gender enum('男','女')                    -- 单选
    -> );
Query OK, 0 rows affected (0.02 sec)

插入数据:

sql 复制代码
insert into votes values('雷锋', '登山,武术', '男');
insert into votes values('Juse', '登山,武术', 2);    -- 2 对应 '女'
insert into votes values('LiLei', '登山', '男');
insert into votes values('LiLei', '篮球', '男');
insert into votes values('HanMeiMei', '游泳', '女');

查询所有数据:

sql 复制代码
mysql> select * from votes;
+-----------+---------------+--------+
| username  | hobby         | gender |
+-----------+---------------+--------+
| 雷锋      | 登山,武术     | 男     |
| Juse      | 登山,武术     | 女     |
| LiLei     | 登山          | 男     |
| LiLei     | 篮球          | 男     |
| HanMeiMei | 游泳          | 女     |
+-----------+---------------+--------+

注意: 使用 = 查询集合类型时,只能精确匹配:

sql 复制代码
mysql> select * from votes where hobby='登山';
+----------+--------+--------+
| username | hobby  | gender |
+----------+--------+--------+
| LiLei    | 登山   | 男     |  -- 只查到恰好只有"登山"的记录
+----------+--------+--------+

正确做法 --- 使用 find_in_set 函数:

sql 复制代码
find_in_set(sub, str_list) : 如果 sub 在 str_list 中,则返回下标;不在则返回 0
str_list 是用逗号分隔的字符串
sql 复制代码
-- 查找所有爱好包含"登山"的人
mysql> select * from votes where find_in_set('登山', hobby);
+----------+---------------+--------+
| username | hobby         | gender |
+----------+---------------+--------+
| 雷锋     | 登山,武术     | 男     |
| Juse     | 登山,武术     | 女     |
| LiLei    | 登山          | 男     |
+----------+---------------+--------+

find_in_set 示例:

sql 复制代码
mysql> select find_in_set('a', 'a,b,c');
+---------------------------+
| find_in_set('a', 'a,b,c') |
+---------------------------+
|                         1 |
+---------------------------+

mysql> select find_in_set('d', 'a,b,c');
+---------------------------+
| find_in_set('d', 'a,b,c') |
+---------------------------+
|                         0 |
+---------------------------+

六、总结

数据类型 常用类型 说明
整数 tinyintintbigint 根据数据范围选择
小数 floatdecimal 精度要求高用 decimal
bit 节省空间存储布尔值
字符串 charvarchar 定长用 char,变长用 varchar
日期时间 datedatetimetimestamp timestamp 自动维护
枚举集合 enumset 单选用 enum,多选用 set

选择原则:

  1. 选择最小够用的类型,节省存储空间
  2. 金额等精度敏感数据用 decimal,不用 float
  3. 主键推荐 bigint,避免 int 溢出风险
  4. 定长数据用 char,变长数据用 varchar
  5. 查询集合类型时用 find_in_set(),不要用 =

相关推荐
二宝哥1 小时前
MySQL 修改密码策略详解:从基础到高级配置
mysql·密码学
一嘴一个橘子2 小时前
MysqL 索引的列 都是什么意思
mysql
秋风渡.5 小时前
MySQL_数据类型知识
数据库·mysql
一嘴一个橘子6 小时前
MysqL 主键索引 就是 聚簇索引 吗
mysql
Whyn6 小时前
MySQL 学习笔记(二)
mysql
raindayinrain8 小时前
mysql原理--补充
数据库·mysql
NWU_白杨9 小时前
三种常用的数据存储技术
数据库·redis·mysql·sqlite
一嘴一个橘子10 小时前
MySqL 的 B+树、 叶子节点、非叶子节点
mysql
小飞侠在吗11 小时前
【MySQL 排错】Navicat 连接 localhost 报 2002 (10061) 完整排查记录(Windows + MySQL 8.4 用户模式)
windows·mysql·adb