数据类型
数据类型
就像收纳盒有不同尺寸——小格子放耳钉、中格子放手表、大格子放围巾——数据库的每列也需要选择合适的"盒子"来存放数据。选对类型,数据既安全又省空间;选错类型,要么浪费存储,要么丢失精度。
1. 核心概念
| 概念 | 说明 |
|---|---|
| 数值类型 | 存储整数和小数,包括 INT、BIGINT、DECIMAL、FLOAT 等 |
| 字符串类型 | 存储文本数据,包括 CHAR、VARCHAR、TEXT |
| 日期类型 | 存储日期和时间,包括 DATE、DATETIME、TIMESTAMP |
| 布尔类型 | 存储真/假值,SQLite 中用 INTEGER(0/1)表示 |
| NULL | 表示"未知"或"缺失",不是空字符串也不是零 |
| 类型选择原则 | 根据数据范围、精度需求和存储效率选择最合适的类型 |
2. 基本语法
数值类型
| 类型 | 说明 | 范围/精度 | 适用场景 |
|---|---|---|---|
INTEGER / INT |
整数 | ±21 亿 | ID、数量、年龄 |
BIGINT |
大整数 | ±9.2×10¹⁸ | 大量数据的 ID、文件大小 |
DECIMAL(p,s) / NUMERIC(p,s) |
精确小数 | p 为总位数,s 为小数位 | 金额、价格(不会丢精度) |
FLOAT / REAL |
浮点数 | 约 7 位有效数字 | 科学计算、近似值 |
DOUBLE |
双精度浮点 | 约 15 位有效数字 | 高精度近似计算 |
SQL
-- DECIMAL 精确存储金额
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
balance DECIMAL(12, 2) -- 最多 12 位,其中 2 位小数
);
-- FLOAT 近似存储
CREATE TABLE measurements (
id INTEGER PRIMARY KEY,
temperature REAL -- 近似值,可能有微小误差
);
💡 提示:金额永远用 DECIMAL,不要用 FLOAT! FLOAT 是近似存储,
0.1 + 0.2 可能等于 0.30000000000000004,这在财务场景中是灾难。
字符串类型
| 类型 | 说明 | 最大长度 | 适用场景 |
|---|---|---|---|
CHAR(n) |
定长字符串 | 255 字节 | 固定长度数据(如性别 M/F、状态码) |
VARCHAR(n) |
变长字符串 | 65535 字节 | 姓名、邮箱、标题 |
TEXT |
长文本 | 无限 | 文章内容、备注、描述 |
SQL
CREATE TABLE articles (
id INTEGER PRIMARY KEY,
title VARCHAR(200), -- 标题,最长 200 字符
status CHAR(1), -- 状态:D=草稿,P=已发布
content TEXT -- 正文,不限长度
);
💡 提示:SQLite 对字符串类型比较宽松,实际上可以存入任意长度的字符串。但为了代码可读性和跨数据库兼容,建议仍然按规范声明类型。
日期类型
| 类型 | 说明 | 格式 | 适用场景 |
|---|---|---|---|
DATE |
日期 | YYYY-MM-DD |
生日、入职日期 |
DATETIME |
日期时间 | YYYY-MM-DD HH:MM:SS |
创建时间、预约时间 |
TIMESTAMP |
时间戳 | 自动管理 | 记录修改时间、跨时区场景 |
SQL
CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_name TEXT,
event_date DATE, -- 只关心日期
created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- 自动记录创建时间
);
💡 提示:SQLite 没有专门的日期类型,通常用
TEXT(ISO 8601 格式如 '2024-01-15')或 INTEGER(Unix 时间戳)存储。SQLite 内置的日期函数(如 DATE()、DATETIME())可以正确处理这些格式。
布尔类型
| 类型 | 说明 | 存储方式 |
|---|---|---|
BOOLEAN |
真/假 | SQLite 中存储为 INTEGER:0=假,1=真 |
BIT |
位值 | MySQL/SQL Server 中使用 |
SQL
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
is_active BOOLEAN DEFAULT 1 -- 1=启用,0=禁用
);
-- 插入布尔值
INSERT INTO users (name, is_active) VALUES ('张三', TRUE); -- 存为 1
INSERT INTO users (name, is_active) VALUES ('李四', FALSE); -- 存为 0
-- 查询时使用布尔值
SELECT * FROM users WHERE is_active = 1;
💡 提示:SQLite 中
TRUE 等价于 1,FALSE 等价于 0。但为了代码可读性,建议使用 TRUE/FALSE 而不是直接写数字。
NULL 的含义
NULL 表示"未知"或"缺失",它不是空字符串 '',也不是数字 0,更不是 FALSE。
SQL
-- NULL 参与运算的结果都是 NULL
SELECT NULL + 1; -- 结果:NULL
SELECT NULL || 'hello'; -- 结果:NULL
-- 判断 NULL 必须用 IS / IS NOT
SELECT * FROM employees WHERE department_id IS NULL; -- ✅ 正确
SELECT * FROM employees WHERE department_id = NULL; -- ❌ 永远返回空
SELECT * FROM employees WHERE department_id IS NOT NULL; -- ✅ 正确
💡 提示:NULL 是新手最容易踩坑的地方。记住两个规则:①判断 NULL 用
IS,不用 =;②NULL 参与任何运算结果都是 NULL。
类型选择最佳实践
| 场景 | 推荐类型 | 原因 |
|---|---|---|
| 主键 ID | INTEGER PRIMARY KEY AUTOINCREMENT |
整数比字符串快,自增方便 |
| 金额/价格 | DECIMAL(10,2) |
精确存储,无舍入误差 |
| 用户名/标题 | VARCHAR(100) |
变长省空间,限制长度防滥用 |
| 文章正文 | TEXT |
不限长度,适合大文本 |
| 日期 | DATE / DATETIME |
语义明确,内置日期函数支持 |
| 是/否标记 | BOOLEAN |
语义清晰,存储紧凑 |
| 枚举状态 | CHAR(1) 或 INTEGER |
比 ENUM 类型更灵活 |
3. 示例代码
示例:创建商品表并验证类型约束(难度⭐)
创建一张商品表,体验不同数据类型的行为。
SQL
-- 创建商品表,指定各列类型
CREATE TABLE products_demo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INTEGER DEFAULT 0,
description TEXT,
is_active BOOLEAN DEFAULT 1,
created_at DATE
);
-- 插入各种类型的数据
INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('机械键盘', 299.50, 100, '青轴87键机械键盘,适合打字', TRUE, '2024-01-15');
INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('无线鼠标', 89.00, 200, NULL, TRUE, '2024-02-20');
-- 查看数据和类型表现
SELECT name, price, stock, description, is_active, created_at
FROM products_demo;
输出:
TEXT
name price stock description is_active created_at
-------- ------- ----- ----------------------- --------- ----------
机械键盘 299.50 100 青轴87键机械键盘,适合打字 1 2024-01-15
无线鼠标 89.00 200 (NULL) 1 2024-02-20
示例:NULL 的运算特性验证(难度⭐⭐)
通过实际查询理解 NULL 的特殊行为。
SQL
-- 创建测试表
CREATE TABLE null_test (
id INTEGER PRIMARY KEY,
value INTEGER
);
INSERT INTO null_test VALUES (1, 10);
INSERT INTO null_test VALUES (2, NULL);
INSERT INTO null_test VALUES (3, 20);
-- NULL 参与算术运算
SELECT id, value, value + 100 AS add_result
FROM null_test;
输出:
TEXT
id value add_result
-- ----- ----------
1 10 110
2 (NULL) (NULL)
3 20 120
SQL
-- 判断 NULL:IS vs =
SELECT id, value,
CASE WHEN value IS NULL THEN '是NULL' ELSE '非NULL' END AS check_result
FROM null_test;
输出:
TEXT
id value check_result
-- ----- ------------
1 10 非NULL
2 (NULL) 是NULL
3 20 非NULL
SQL
-- NULL 与聚合函数:COUNT 不计 NULL,SUM/AVG 忽略 NULL
SELECT COUNT(value) AS count_val, -- 2(不计 NULL)
COUNT(*) AS count_all, -- 3(计所有行)
SUM(value) AS sum_val, -- 30(忽略 NULL)
AVG(value) AS avg_val -- 15(30/2,不是30/3)
FROM null_test;
输出:
TEXT
count_val count_all sum_val avg_val
--------- --------- ------- -------
2 3 30 15.0
4. 常见应用场景
场景一:设计用户注册表
根据业务需求选择合适的类型:
SQL
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) NOT NULL UNIQUE, -- 用户名,唯一且非空
email VARCHAR(100) NOT NULL UNIQUE, -- 邮箱
password_hash CHAR(64) NOT NULL, -- SHA256 哈希,固定 64 字符
age INTEGER CHECK (age >= 0 AND age <= 150), -- 年龄,合理范围校验
balance DECIMAL(12, 2) DEFAULT 0.00, -- 账户余额,精确到分
bio TEXT, -- 个人简介,不限长度
is_verified BOOLEAN DEFAULT 0, -- 是否验证邮箱
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
场景二:处理 NULL 的默认值
用 COALESCE 函数为 NULL 提供默认值:
SQL
-- 查询员工信息,部门为空时显示"未分配"
SELECT e.name,
COALESCE(d.name, '未分配') AS department,
COALESCE(e.salary, 0) AS salary
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;
❓ 常见问题
Q DECIMAL(10,2) 和 FLOAT 都能存小数,有什么区别?
A DECIMAL 是精确存储,适合金额等不能有误差的场景;FLOAT 是近似存储,计算速度快但有微小误差。简单记:钱用 DECIMAL,科学计算用 FLOAT。
Q CHAR 和 VARCHAR 怎么选?
A 如果数据长度固定(如性别 M/F、MD5 哈希),用 CHAR 更高效;如果长度不固定(如姓名、标题),用 VARCHAR 更省空间。实际开发中 VARCHAR 用得更多。
Q NULL 和空字符串 '' 有什么区别?
A NULL 表示"不知道/没有值",空字符串表示"知道值是什么,值是空的"。比如"中间名"列,外国人可能没有中间名(NULL),中国人可能有中间名但为空字符串('')。在聚合函数中,COUNT(列) 不计 NULL 但会计空字符串。
Q SQLite 的类型系统和其他数据库有什么不同?
A SQLite 使用动态类型系统,列的类型声明更像是"建议"而非强制约束。你可以往 INTEGER 列插入字符串(虽然不推荐)。MySQL、PostgreSQL 等是严格类型系统,类型不匹配会报错。为了代码可移植性,建议按规范使用类型。
📖 小节
- 数值类型:整数用 INT/BIGINT,精确小数用 DECIMAL(金额必选),近似值用 FLOAT
- 字符串类型:固定长度用 CHAR,变长用 VARCHAR,大文本用 TEXT
- 日期类型:DATE 存日期,DATETIME 存日期时间,TIMESTAMP 自动管理
- 布尔类型:BOOLEAN 存储 TRUE/FALSE,SQLite 中实际为 INTEGER 0/1
- NULL 表示"未知",判断用
IS NULL而非= NULL,NULL 参与运算结果仍为 NULL - 类型选择原则:根据数据范围、精度需求、存储效率综合考虑,金额必用 DECIMAL
📝 作业
练习 1(⭐)
设计一个"图书馆借阅"表,包含以下字段,选择合适的数据类型:
- 借阅 ID(主键)
- 书名(最长 200 字符)
- ISBN(固定 13 位)
- 借阅人姓名
- 借出日期
- 应还日期
- 是否归还
- 备注(可为空)
练习 2(⭐⭐)
创建上题的表并插入 5 条数据,然后编写查询:
- 查询所有未归还的借阅记录
- 查询备注为 NULL 的记录
- 计算所有未归还记录的数量(注意 NULL 的处理)



