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. 数值类型详解
整数类型包括 TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,这是一个整型家族,对应不同的字节数也就对应不同的数据范围。可以用 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函数。
- 实践建议:根据业务需求选择合适类型,利用类型约束减少应用层校验。