3. SQLite 数据类型体系:动态类型、存储类与亲和性规则
核心观点:SQLite 采用动态类型系统,字段不强制绑定固定数据类型,而是通过存储类(Storage Class)和类型亲和性(Type Affinity)实现灵活性与传统 SQL 数据类型之间的平衡。理解这套机制是正确使用 SQLite 的前提。
3.1 动态类型与静态类型的本质差异
| 对比维度 | 静态类型数据库(MySQL/PostgreSQL) | SQLite 动态类型 |
|---|---|---|
| 列定义 | 严格绑定类型(如 INT、VARCHAR(100)) | 仅声明类型建议(如 INTEGER、TEXT) |
| 存储值 | 必须符合列类型,否则报错或隐式转换 | 每个值独立记录自身的存储类,与列声明无关 |
| 灵活性 | 高一致性,低灵活性 | 高灵活性,但需注意隐式转换风险 |
| 典型应用 | 企业级 OLTP、强约束场景 | 嵌入式、原型、配置存储、边缘设备 |
在 MySQL 中,如果创建 CREATE TABLE t (c INT),则列 c 只能存储整数值;若插入字符串 'abc',会导致转换错误或插入 0。SQLite 则允许任何列插入任何类型的值,即使在 INTEGER 列中写入文本 'hello' 也不会报错——该值会以 TEXT 存储类保存。
3.2 五大存储类
SQLite 每个值在物理存储上属于以下五种之一,称为存储类:
- NULL —— 空值,不占数据空间。
- INTEGER —— 有符号整数,根据值大小使用 1~8 字节可变长度存储。
- REAL —— 浮点数,固定 8 字节 IEEE 754 双精度。
- TEXT —— 字符串,使用数据库编码(UTF‑8/UTF‑16LE/UTF‑16BE)存储。
- BLOB —— 二进制大对象,原样存储,不进行编码转换。
注意:SQLite 没有独立的 BOOLEAN 或 DATETIME 存储类。布尔值用 INTEGER 0/1 表示,日期时间用 TEXT(ISO‑8601)或 REAL(儒略日)或 INTEGER(unix 时间戳)表示。
3.3 类型亲和性规则
当建表语句包含传统类型名(如 INT、CHAR、DOUBLE)时,SQLite 会根据亲和性规则将其映射为五种存储类之一,从而决定插入值时的自动转换倾向。规则优先级如下:
- INTEGER AFFINITY —— 声明包含
INT关键字(如INT、BIGINT、INTEGER) - TEXT AFFINITY —— 包含
CHAR、CLOB、TEXT关键字(如VARCHAR(255)、CHAR(10)) - REAL AFFINITY —— 包含
REAL、FLOAT、DOUBLE关键字 - NUMERIC AFFINITY —— 包含
NUMERIC、DECIMAL、BOOLEAN、DATE、DATETIME等无明确 INT/CHAR/FLOAT 关键字的类型 - BLOB AFFINITY —— 不带任何类型名或使用
BLOB关键字
实际插入值时,SQLite 会按以下顺序尝试转换(以 INTEGER 亲和性列为例):
- 若值为
TEXT且可以无损解析为整数(如'123'),则转换为INTEGER存储。 - 若值为
REAL且小数部分为零(如12.0),则转换为INTEGER。 - 否则保持原存储类。
常见误区:认为 CREATE TABLE t (a INTEGER) 后,插入 'abc' 会报错。实际上 SQLite 不会报错,该值会以 TEXT 存储类保存,且不会自动转换为 0——与 MySQL 不同。
3.4 常见误区
- 误区一:SQLite 没有数据类型。
事实:SQLite 有严格的存储类,只是类型绑定在值上而非列上。 - 误区二:INTEGER 列可以安全存放任意大整数。
事实:INTEGER 存储类支持最大 8 字节有符号整数(-9.22e18 ~ 9.22e18),超范围将转为 REAL 或截断。 - 误区三:TEXT 列插入数字会损失精度。
事实:若声明为TEXT列,插入数字会作为 TEXT 存储,不会丢失精度,但比较时按字符串规则(词典序)进行,需要小心。 - 误区四:BLOB 和 TEXT 在存储上完全一样。
事实:BLOB 不进行字符编码转换,TEXT 会根据数据库编码进行转换,且排序方式不同。
3.5 应用边界与最佳实践
| 场景 | 建议 | 理由 |
|---|---|---|
| 主键自增列 | 使用 INTEGER PRIMARY KEY | 自动获得 ROWID 优化,列类型为 INTEGER 亲和性 |
| 存储 JSON 文档 | 使用 TEXT 列 | SQLite 3.9+ 有内置 JSON 函数,TEXT 存储保留原始格式 |
| 存储二进制小文件(< 10KB) | 使用 BLOB 列 | 避免文件系统碎片,但注意备份性能 |
| 需要严格类型约束 | 在应用层校验,或启用 STRICT 表(SQLite 3.37+) | STRICT 模式强制值类型必须匹配列声明 |
3.6 练习题
- (选择)SQLite 中,
INSERT INTO t (col) VALUES (3.14)且col列声明为INTEGER,实际存储为哪个存储类?
A. INTEGER B. REAL C. TEXT D. NUMERIC - (判断)若列声明为
VARCHAR(50),插入整数 42 后可以用索引加速WHERE col = 42查询吗?说明理由。 - (填空)SQLite 五大存储类分别是 ________、________、________、________、________。
- (简答)设计一个标签表,要求标签名称(最长 200 字符)、创建时间(精确到秒)、关联图片(PNG 文件,平均 50KB)。应该如何选择列类型?给出建表语句片段(可使用 SQLite 方言)。
实用清单:亲和性规则速查
-- 整数亲和性
INT, INTEGER, TINYINT, SMALLINT, MEDIUMINT, BIGINT, UNSIGNED BIG INT, INT2, INT8
-- 文本亲和性
CHARACTER, VARCHAR, VARYING CHARACTER, NCHAR, NATIVE CHARACTER, NVARCHAR, TEXT, CLOB
-- 实数亲和性
REAL, DOUBLE, DOUBLE PRECISION, FLOAT
-- 数值亲和性
NUMERIC, DECIMAL, BOOLEAN, DATE, DATETIME, TIMESTAMP
-- 二进制亲和性
BLOB 或不声明任何类型名