SQL 数据类型
数据类型定义了列可以存储的数据种类。本章介绍 SQL 中常用的数据类型。
数值类型
整数类型
| 类型 | 存储 | 范围 | 说明 |
|---|---|---|---|
| TINYINT | 1字节 | -128 ~ 127 | 小整数 |
| SMALLINT | 2字节 | -32768 ~ 32767 | 短整数 |
| MEDIUMINT | 3字节 | -8388608 ~ 8388607 | 中等整数 |
| INT/INTEGER | 4字节 | -21亿 ~ 21亿 | 标准整数 |
| BIGINT | 8字节 | 非常大 | 大整数 |
CREATE TABLE numbers (
tiny_col TINYINT,
small_col SMALLINT,
int_col INT,
big_col BIGINT
);
INSERT INTO numbers VALUES (127, 32767, 2147483647, 9223372036854775807);
无符号整数
MySQL 支持无符号整数(UNSIGNED),范围从 0 开始:
CREATE TABLE unsigned_example (
id INT UNSIGNED, -- 0 ~ 4294967295
tiny TINYINT UNSIGNED -- 0 ~ 255
);
-- 错误:超出范围
INSERT INTO unsigned_example VALUES (-1, 100); -- Error
浮点类型
| 类型 | 说明 |
|---|---|
| FLOAT | 单精度浮点数,4字节 |
| DOUBLE | 双精度浮点数,8字节 |
| DECIMAL/NUMERIC | 精确小数 |
CREATE TABLE floats (
float_col FLOAT,
double_col DOUBLE,
decimal_col DECIMAL(10, 2) -- 10位总长度,2位小数
);
INSERT INTO floats VALUES (3.14159, 3.14159265358979, 12345.67);
DECIMAL 精确计算
对于金额等需要精确计算的场景,使用 DECIMAL:
-- 使用 DECIMAL 存储金额
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10, 2) -- 最大 99999999.99
);
-- FLOAT/DOUBLE 可能有精度问题
SELECT 0.1 + 0.2; -- 可能返回 0.30000000000000004
SELECT CAST(0.1 AS DECIMAL(10,2)) + CAST(0.2 AS DECIMAL(10,2)); -- 0.30
字符串类型
定长字符串
CHAR(n) 固定长度,不足补空格:
CREATE TABLE char_example (
code CHAR(10), -- 固定10字符
status CHAR(1) -- 固定1字符
);
INSERT INTO char_example VALUES ('ABC', 'A');
-- 实际存储: 'ABC ' 和 'A'
变长字符串
VARCHAR(n) 可变长度,按实际存储:
CREATE TABLE varchar_example (
name VARCHAR(100), -- 最多100字符
email VARCHAR(255) -- 最多255字符
);
INSERT INTO varchar_example VALUES ('张三', '[email protected]');
-- 实际存储: '张三' 和 '[email protected]'
CHAR vs VARCHAR
| 类型 | 存储 | 适用场景 |
|---|---|---|
| CHAR | 固定长度 | 手机号、身份证、状态码 |
| VARCHAR | 变长长度 | 姓名、邮箱、地址 |
-- 手机号:固定11位,用 CHAR
phone CHAR(11)
-- 姓名:长度不固定,用 VARCHAR
name VARCHAR(50)
-- 状态码:固定1位,用 CHAR
status CHAR(1)
大文本类型
| 类型 | 最大长度 | 说明 |
|---|---|---|
| TINYTEXT | 255字节 | 小文本 |
| TEXT | 65KB | 普通文本 |
| MEDIUMTEXT | 16MB | 中等文本 |
| LONGTEXT | 4GB | 大文本 |
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(200),
content TEXT, -- 文章内容
extra LONGTEXT -- 额外信息
);
日期时间类型
日期类型
| 类型 | 格式 | 范围 |
|---|---|---|
| DATE | YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 |
| TIME | HH:MM:SS | -838:59:59 ~ 838:59:59 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 1000-01-01 ~ 9999-12-31 |
| TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 ~ 2038-01-19 |
| YEAR | YYYY | 1901 ~ 2155 |
CREATE TABLE events (
id INT PRIMARY KEY,
event_date DATE,
event_time TIME,
created_at DATETIME,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO events (id, event_date, event_time, created_at)
VALUES (1, '2024-01-15', '14:30:00', '2024-01-15 14:30:00');
DATETIME vs TIMESTAMP
| 特性 | DATETIME | TIMESTAMP |
|---|---|---|
| 范围 | 1000-9999年 | 1970-2038年 |
| 存储 | 8字节 | 4字节 |
| 时区 | 不转换 | 自动转换 |
| 默认值 | 可设置 | 可自动更新 |
CREATE TABLE time_test (
id INT PRIMARY KEY,
dt DATETIME,
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- TIMESTAMP 会根据时区自动转换
-- DATETIME 存储什么就显示什么
日期函数
-- 当前日期时间
SELECT NOW(); -- 2024-01-15 14:30:00
SELECT CURDATE(); -- 2024-01-15
SELECT CURTIME(); -- 14:30:00
-- 日期计算
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY); -- 加7天
SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH); -- 减1月
SELECT DATEDIFF('2024-01-15', '2024-01-01'); -- 相差天数
-- 日期格式化
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日'); -- 2024年01月15日
布尔类型
MySQL 没有真正的布尔类型,使用 TINYINT(1) 模拟:
CREATE TABLE flags (
id INT PRIMARY KEY,
is_active BOOLEAN, -- 实际是 TINYINT(1)
is_deleted BOOL -- 同上
);
INSERT INTO flags VALUES (1, TRUE, FALSE);
INSERT INTO flags VALUES (2, 1, 0); -- 等价写法
SELECT * FROM flags WHERE is_active = TRUE;
SELECT * FROM flags WHERE is_active = 1; -- 等价写法
二进制类型
用于存储二进制数据(图片、文件等):
| 类型 | 最大长度 |
|---|---|
| BLOB | 65KB |
| MEDIUMBLOB | 16MB |
| LONGBLOB | 4GB |
CREATE TABLE files (
id INT PRIMARY KEY,
name VARCHAR(255),
data LONGBLOB -- 存储文件数据
);
注意
不建议在数据库中存储大文件,建议存储文件路径。
JSON 类型
MySQL 5.7+ 和 PostgreSQL 支持 JSON 类型:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
settings JSON,
profile JSON
);
INSERT INTO users VALUES (
1,
'张三',
'{"theme": "dark", "language": "zh"}',
'{"age": 25, "city": "北京"}'
);
-- 查询 JSON 字段
SELECT name, settings->>'$.theme' AS theme FROM users;
-- JSON 函数
SELECT JSON_EXTRACT(profile, '$.age') FROM users;
SELECT JSON_SET(settings, '$.theme', 'light') FROM users;
枚举和集合
ENUM 枚举
从预定义值中选择一个:
CREATE TABLE orders (
id INT PRIMARY KEY,
status ENUM('pending', 'processing', 'shipped', 'completed', 'cancelled')
);
INSERT INTO orders VALUES (1, 'pending');
INSERT INTO orders VALUES (2, 'processing');
-- 错误:不在枚举值中
INSERT INTO orders VALUES (3, 'unknown'); -- Error 或空值
SET 集合
从预定义值中选择多个:
CREATE TABLE articles (
id INT PRIMARY KEY,
tags SET('tech', 'life', 'travel', 'food')
);
INSERT INTO articles VALUES (1, 'tech,life');
INSERT INTO articles VALUES (2, 'travel,food');
-- 查询
SELECT * FROM articles WHERE FIND_IN_SET('tech', tags);
类型转换
使用 CAST 或 CONVERT 函数:
-- 字符串转数字
SELECT CAST('123' AS UNSIGNED);
SELECT CONVERT('123', UNSIGNED);
-- 数字转字符串
SELECT CAST(123 AS CHAR);
-- 日期转换
SELECT CAST('2024-01-15' AS DATE);
SELECT STR_TO_DATE('2024-01-15', '%Y-%m-%d');
PostgreSQL 特有类型
PostgreSQL 提供更丰富的类型:
-- 数组类型
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
tags TEXT[] -- 文本数组
);
INSERT INTO posts (tags) VALUES (ARRAY['tech', 'sql']);
INSERT INTO posts (tags) VALUES ('{tech,sql}');
-- UUID 类型
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
);
-- 网络地址类型
CREATE TABLE network (
ip INET, -- IP地址
mac MACADDR -- MAC地址
);
数据类型选择建议
| 场景 | 推荐类型 |
|---|---|
| 主键 | INT AUTO_INCREMENT 或 BIGINT |
| 金额 | DECIMAL(10, 2) |
| 手机号 | CHAR(11) |
| 邮箱 | VARCHAR(255) |
| 姓名 | VARCHAR(50) |
| 文章内容 | TEXT |
| 创建时间 | DATETIME 或 TIMESTAMP |
| 状态 | ENUM 或 TINYINT |
| 开关 | BOOLEAN |
| JSON 数据 | JSON |
小结
本章我们学习了:
- 数值类型(整数、浮点、DECIMAL)
- 字符串类型(CHAR、VARCHAR、TEXT)
- 日期时间类型(DATE、DATETIME、TIMESTAMP)
- 布尔类型
- JSON 类型
- 枚举和集合
- 类型转换
练习
- 创建一个产品表,选择合适的数据类型
- 设计一个订单表,包含金额、日期、状态字段
- 练习日期函数的使用
- 使用 JSON 类型存储用户配置