MySQL 数据类型详解

MySQL 数据类型详解

  • [1. 数据类型分类概览](#1. 数据类型分类概览)
  • [2. 数值类型详解](#2. 数值类型详解)
  • [3. bit 类型基本语法](#3. bit 类型基本语法)
    • [3.1 注意事项](#3.1 注意事项)
    • [3.2 示例代码](#3.2 示例代码)
  • [4. 小数类型](#4. 小数类型)
    • [4.1 float 语法](#4.1 float 语法)
      • [4.1.1 特点](#4.1.1 特点)
      • [4.1.2 示例代码](#4.1.2 示例代码)
    • [4.2 decimal 语法](#4.2 decimal 语法)
      • [4.2.1 对比 float](#4.2.1 对比 float)
      • [4.2.2 示例代码](#4.2.2 示例代码)
    • [4.3 建议](#4.3 建议)
  • [5. 字符串类型](#5. 字符串类型)
    • [5.1 char](#5.1 char)
    • [5.2 varchar](#5.2 varchar)
    • [5.3 char 和 varchar 比较](#5.3 char 和 varchar 比较)
  • [6. 日期和时间类型](#6. 日期和时间类型)
  • [7. enum 和 set](#7. enum 和 set)
    • [7.1 enum(枚举)](#7.1 enum(枚举))
    • [7.2 set(集合)](#7.2 set(集合))
    • [7.3 enum 和 set 的查找](#7.3 enum 和 set 的查找)
  • [8. 补充总结](#8. 补充总结)

1. 数据类型分类概览

分类 类型 说明
数值类型 BIT(M) 位类型。M指定位数,默认值1,范围1-64
TINYINT [UNSIGNED] 带符号的范围-128127,无符号范围0255。默认有符号
BOOL 使用0和1表示真和假
SMALLINT [UNSIGNED] 带符号是-2^15 到 215-1,无符号是0~216-1
INT [UNSIGNED] 带符号是-2^31 到 231-1,无符号是0~232-1
BIGINT [UNSIGNED] 带符号是-2^63 到 263-1,无符号是0~264-1
FLOAT(M,D) [UNSIGNED] M指定位显示长度,d指定位小数位数,占用4字节
DOUBLE(M,D) [UNSIGNED] 表示比float精度更大的小数,占用空间8字节
DECIMAL(M,D) [UNSIGNED] 定点数,M指定位长度,D表示小数点的位数
文本、二进制类型 CHAR(size) 固定长度字符串,最大255
VARCHAR(size) 可变长度字符串,最大长度65535字节
BLOB 二进制数据
TEXT 大文本,不支持全文索引,不支持默认值
时间日期 DATE / DATETIME / TIMESTAMP 日期类型:DATE(yyyy-mm-dd)、DATETIME(yyyy-mm-dd hh:mm:ss)、TIMESTAMP时间戳
String类型 ENUM ENUM是一个字符串对象,其值来自表创建时在列规定中显示枚举的一列值
SET SET是一个字符串对象,可以省略或多个值,其值来自表创建时规定的允许的一列值。指定包括多个set成员的set列值时各成员之间用逗号间隔开,这样set成员值本身不包含逗号

2. 数值类型详解

整数类型包括 TINYINTSMALLINTMEDIUMINTINTBIGINT,这是一个整型家族,对应不同的字节数也就对应不同的数据范围。可以用 C++ 中的整型家族来对比说明:

MySQL 类型 字节 有符号范围 无符号范围 类比 C++ 类型
TINYINT 1 -128 ~ 127 0 ~ 255 signed char / unsigned char
SMALLINT 2 -32768 ~ 32767 0 ~ 65535 short / unsigned short
MEDIUMINT 3 -8388608 ~ 8388607 0 ~ 16777215 无直接对应(3字节)
INT 4 -2147483648 ~ 2147483647 0 ~ 4294967295 int / unsigned int
BIGINT 8 -9223372036854775808 ~ 9223372036854775807 0 ~ 18446744073709551615 long long / unsigned long long

在 MySQL 中,插入的数据如果超出该列数据类型的范围会直接拦截并且报错,不会发生截断、隐式类型转化之类的操作。MySQL 必须保证插入数据的完整性。如果数据已经插入到 MySQL 中,就证明该数据一定是合法的。在 MySQL 中,数据类型本身也是一种约束,确保使用者正确插入数据。

在 MySQL 表中建立属性列时,列的名称在前,类型在后。整型可以指定是有符号的和无符号的,默认是有符号的。可以通过 UNSIGNED 来说明某个字段是无符号的。

数值越界测试:

sql 复制代码
mysql> create table ttl(num tinyint);
Query OK, 0 rows affected (0.02 sec)

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

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

mysql> select * from ttl;
+------+
| num  |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

无符号案例:

sql 复制代码
mysql> create table tt2(num tinyint unsigned);
Query OK, 0 rows affected (0.01 sec)

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

mysql> insert into tt2 values(255);
Query OK, 1 row affected (0.02 sec)

mysql> select * from tt2;
+------+
| num  |
+------+
|  255 |
+------+
1 row in set (0.00 sec)

注意:尽量不使用 unsigned,对于 int 类型可能存放不下的数据,int unsigned 同样可能存放不下,与其如此,还不如设计时,将 int 类型提升为 bigint 类型。

3. bit 类型基本语法

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

3.1 注意事项

  • bit 字段在显示时,按照 ASCII 码对应的值显示,可能无法显示某些字符。
  • 可使用 hex() 函数转为十六进制显示。
  • 若仅需存储0或1,建议定义 bit(1) 以节省空间。

3.2 示例代码

sql 复制代码
-- 创建表
CREATE TABLE tt4 (id INT, a BIT(8));

-- 插入数据
INSERT INTO tt4 VALUES(10, 10);
INSERT INTO tt4 VALUES(65, 65);

-- 查询结果异常(显示为空或字符)
SELECT * FROM tt4;

-- bit(1) 示例
CREATE TABLE tt5(gender BIT(1));
INSERT INTO tt5 VALUES(0);
INSERT INTO tt5 VALUES(1);
INSERT INTO tt5 VALUES(2);  -- 越界报错

4. 小数类型

4.1 float 语法

float(m, d) unsigned

  • m:显示长度
  • d:小数位数
  • 占用空间:4字节
  • 范围示例:float(4,2) 表示 -99.99 ~ 99.99
  • 默认保留两位小数(float(X,2))

4.1.1 特点

  • 采用二进制科学计数法存储,可能存在精度损失。
  • 超出范围会四舍五入,若仍超范围则报错。
  • unsigned 仅移除负数范围,最小值仍为0。

4.1.2 示例代码

sql 复制代码
-- 创建表
CREATE TABLE tt6(id INT, salary FLOAT(4,2));

-- 插入数据(四舍五入)
INSERT INTO tt6 VALUES(100, -99.99);
INSERT INTO tt6 VALUES(101, -99.991);  -- 四舍五入为 -99.99

-- 无符号表示范围
CREATE TABLE tt7(id INT, salary FLOAT(4,2) UNSIGNED);
INSERT INTO tt7 VALUES(100, -0.1);  -- 越界警告
INSERT INTO tt7 VALUES(100, 99.99);

4.2 decimal 语法

decimal(m, d) unsigned

  • 定点数,精度更高
  • 范围示例:decimal(5,2) 表示 -999.99 ~ 999.99
  • 最大整数位数 m:65,小数位数 d:30

4.2.1 对比 float

  • decimal 精度更准确,适合高精度需求。
  • float 精度约7位,decimal 无精度损失。

4.2.2 示例代码

sql 复制代码
-- 创建表对比精度
CREATE TABLE tt8 (id INT, salary FLOAT(10,8), salary2 DECIMAL(10,8));

-- 插入数据
INSERT INTO tt8 VALUES(100, 23.12345612, 23.12345612);

-- 查询显示 decimal 更精确
SELECT * FROM tt8;

4.3 建议

  • 高精度场景推荐使用 decimal。

5. 字符串类型

5.1 char

语法char(L):固定长度字符串,L 是可以存储的长度,单位为字符,最大长度值可以为 255。

说明

设置 CHAR(2) 表示能插入两个字符。插入 'a''ab' 可以,'abc' 不行;插入 '中''中国' 可以,'中国人' 不行。在 MySQL 中,一个 "字符" 代表一个符号,不管底层占用多少字节。

案例

sql 复制代码
mysql> create table tt9(id int, name char(2));
Query OK, 0 rows affected (0.00 sec)

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 rows in set (0.00 sec)

注意

char(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

5.2 varchar

语法varchar(L):可变长度字符串,L 表示字符长度,最大长度 65535 个字节。

说明

varchar 最大是 65535 字节,不是字符。varchar(len)len 值与表的编码密切相关:

  • varchar 长度可指定为 0 到 65535 之间的值,但有 1~3 个字节用于记录数据大小,有效字节数为 65532。
  • UTF-8 编码时,varchar(n)n 最大值是 65532/3 = 21844(UTF-8 中一个字符占 3 字节)。
  • GBK 编码时,varchar(n)n 最大值是 65532/2 = 32766(GBK 中一个字符占 2 字节)。

char 和 varchar 的区别

  • char 类似于数组,定义时分配固定空间,未用完也不会回收。
  • varchar(len)len 是最大长度上限,实际分配空间按实际数据长度算。
  • varchar 需要 1~3 字节记录实际数据长度,有效字节数最多为 65532。
  • 同一行中所有字段总字节数必须小于 65535。

验证

sql 复制代码
mysql> create table ttl(name varchar(21845)) charset=utf8;   -- 超过 21844 报错
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs

mysql> create table ttl(name varchar(21844)) charset=utf8;
Query OK, 0 rows affected (0.01 sec)

5.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' × × 数据超过长度 数据超过长度

如何选择

  • 数据长度固定(如身份证、手机号、MD5)使用 char
  • 数据长度变化(如名字、地址)使用 varchar,需确保最长数据能存入。
  • char 浪费空间但效率高;varchar 节省空间但效率低。

6. 日期和时间类型

常用日期类型:

类型 格式 范围 字节 说明
date 'yyyy-mm-dd' 1000-01-01 到 9999-12-31 3 年月日,需手动插入
datetime 'yyyy-mm-dd HH:ii:ss' 1000-01-01 00:00:00 到 9999-12-31 23:59:59 8 年月日时分秒,需手动插入
timestamp 'yyyy-mm-dd HH:ii:ss' 1970-01-01 00:00:01 到 2038-01-19 03:14:07 4 时间戳,自动更新

案例

sql 复制代码
-- 创建表
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
Query OK, 0 rows affected (0.01 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 | 2017-11-12 18:28:55 |  -- 时间戳自动填充当前时间
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

-- 更新数据
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 |  -- 时间戳自动更新
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

7. enum 和 set

7.1 enum(枚举)

语法:

sql 复制代码
enum('选项1','选项2','选项3',...)
  • 枚举类型为"单选",单元格实际存储一个值,底层以数字(1,2,3,...)表示选项,最多支持 65535 个选项。
  • 插入时可使用选项值或对应数字编号(从 1 开始)。未指定值时,默认为 NULL(若允许)或第一个枚举值(若不允许)。

示例:

sql 复制代码
CREATE TABLE votes(
    username VARCHAR(30),
    hobby SET('登山','游泳','篮球','武术'),  -- 多选类型
    gender ENUM('男','女')                   -- 单选类型
);

插入数据:

sql 复制代码
INSERT INTO votes VALUES('张三','登山,武术','男');
INSERT INTO votes VALUES('Juse','登山,武术',2);  -- 数字 2 表示 '女'

查询:

sql 复制代码
SELECT * FROM votes WHERE gender = 2;  -- 返回 gender 为 '女' 的记录

7.2 set(集合)

语法:

sql 复制代码
set('选项值1','选项值2','选项值3',...)
  • 集合类型为"多选",单元格可存储多个值,底层以位掩码(1,2,4,8,...)表示选项,最多支持 64 个选项。
  • 插入时用逗号分隔多个选项值,或使用数字(二进制位掩码)。例如:
    • 3(二进制 11)对应选中前两个选项。
    • 0 表示空集合("")。

注意事项:

  • 直接插入数字时,MySQL 将数字解析为选项的位掩码组合。
  • 插入无效值会报错或存储为空集合。

7.3 enum 和 set 的查找

示例数据:

username hobby gender
张三 登山,武术
Juse 登山,武术
LiLei 登山

问题:直接使用 WHERE hobby='登山' 仅能查询唯一爱好为"登山"的行。

解决方案:

  • 使用 FIND_IN_SET 函数查询包含指定选项的记录:
sql 复制代码
SELECT * FROM votes WHERE FIND_IN_SET('登山', hobby);

结果返回所有 hobby 包含"登山"的行。

8. 补充总结

  • 数据类型即约束:MySQL 严格检查数据合法性,确保存储完整性。
  • 精度选择 :精确数据(如金额)用 DECIMAL,统计用 FLOAT/DOUBLE
  • 字符串选择 :定长用 CHAR,变长用 VARCHAR,注意字符集影响最大长度。
  • 时间戳TIMESTAMP 适合自动记录最后修改时间。
  • 枚举/集合
    • ENUM 为单选,SET 为多选。
    • 查询多选时使用 FIND_IN_SET 函数。
  • 实践建议:根据业务需求选择合适类型,利用类型约束减少应用层校验。
相关推荐
江屿风5 小时前
【C++笔记】List流食般投喂
开发语言·c++·笔记·list
信仰8745 小时前
HCIA-华为数通基础理论与实践08
网络·笔记·华为
编程圈子6 小时前
操作系统学习14 IDT + PIC + 键盘中断
android·学习·计算机外设
齊家治國平天下13 小时前
Android 14 Vehicle HAL (VHAL) 设计与实现深度解析
android·aaos·carservice·车载开发·android 14·vhal·vehicle hal
Cx330❀14 小时前
【MySQL基础】一文吃透“表的约束”:从 Null/Default 到主外键的终极安全法则
linux·服务器·数据库·c++·mysql·安全
大阳光男孩14 小时前
Spring Boot 整合 Debezium 实现 MySQL 增量数据监听(嵌入式版)
spring boot·后端·mysql
我科绝伦(Huanhuan Zhou)15 小时前
MySQL极端场景数据丢失防护:从Crash-Safe到异地备份
数据库·mysql
笨蛋不要掉眼泪15 小时前
MySQL架构揭秘:MVCC解决读一致性问题
数据库·mysql·架构
一只小菜鸡..18 小时前
Stanford CS144 学习笔记 (四):网络拥塞控制与 AIMD 算法
网络·笔记·学习