SQLite数据类型
目录
1 SQLite的类型概述
1.1 存储类(Storage Classes)
1.2 类型亲和性(Type Affinity)
2 类型亲和性分配规则
3 数据类型详细说明
3.1 INTEGER类型
3.2 REAL类型
3.3 TEXT类型
3.4 BLOB类型
3.5 NULL类型
3.6 NUMERIC类型
4 特殊类型和类型转换
4.1 BOOLEAN
4.2 DATE, DATETIME, TIMESTAMP
4.3 DECIMAL和精确数值
5 类型转换和兼容性
5.2 显式类型转换
5.2 隐式类型转换规则
5.3 类型灵活性示例
6 数据类型的实际应用示例
6.1 主键和ROWID
6.2 处理二进制数据(BLOB)
6.3 存储和查询JSON数据
6.4 日期时间处理
6.5 高效存储大表的考虑
7 数据类型的最佳实践
8 SQLite类型系统的优缺点
8.1 优点
8.2 缺点
9 总结
SQLite采用了一种不同于大多数其他SQL数据库的类型系统,称为"动态类型系统"或"存储类系统"。下面将详细介绍SQLite的数据类型体系、类型亲和性、类型存储及其使用特点。
1 SQLite的类型概述
1.1 存储类(Storage Classes)
SQLite有5种基本存储类:
存储类 | 描述 | 存储方式 |
---|---|---|
NULL | 表示空值 | NULL |
INTEGER | 有符号整数 | 1, 2, 3, 4, 6或8字节,取决于存储的数值大小 |
REAL | 浮点数 | 8字节的IEEE浮点数 |
TEXT | 文本字符串 | UTF-8、UTF-16BE或UTF-16LE编码 |
BLOB | 二进制大对象 | 按照输入存储(完全保留) |
1.2 类型亲和性(Type Affinity)
当创建表时,SQLite会为每列分配一种类型亲和性。类型亲和性决定了SQLite如何尝试转换存储的值:
INTEGER - 倾向于将数据存储为INTEGER
TEXT - 倾向于将数据存储为TEXT
REAL - 倾向于将数据存储为REAL
NUMERIC - 尝试存储为INTEGER或REAL;如果不行则为TEXT
BLOB - 不做任何类型转换,按原样存储
2 类型亲和性分配规则
SQLite根据列的声明类型决定其类型亲和性,规则如下:
INTEGER亲和性:如果类型包含字符串"INT"(不区分大小写)
例如:INT, INTEGER, BIGINT, SMALLINT, TINYINT
TEXT亲和性:如果类型包含以下任一字符串(不区分大小写):
“CHAR”, “CLOB”, “TEXT”
例如:VARCHAR, NCHAR, CLOB, TEXT
BLOB亲和性:仅当列的声明类型为"BLOB"(不区分大小写)
REAL亲和性:如果类型包含以下任一字符串(不区分大小写):
“REAL”, “FLOA”, “DOUB”
例如:REAL, FLOAT, DOUBLE, DOUBLE PRECISION
NUMERIC亲和性:所有其他情况,包括:
NUMERIC, DECIMAL, BOOLEAN, DATE, DATETIME
3 数据类型详细说明
3.1 INTEGER类型
CREATE TABLE example (id INTEGER PRIMARY KEY,count INTEGER,big_num BIGINT,small_num SMALLINT
);
注意事项:
存储有符号整数值
最大可达8字节(64位),范围:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
可用于主键(特别是INTEGER PRIMARY KEY)
与JavaScript不同,SQLite的INTEGER可以精确表示大整数,不会有精度损失
3.2 REAL类型
CREATE TABLE measurements (temperature REAL,distance FLOAT,calculation DOUBLE
);
注意事项:
存储8字节的IEEE浮点数
范围约为±1.79×10^308,精度为15-16位十进制数字
所有FLOAT, DOUBLE等类型都会映射为REAL
受浮点数固有的精度限制影响
3.3 TEXT类型
CREATE TABLE messages (message TEXT,name VARCHAR(100),description NVARCHAR(200)
);
注意事项:
存储文本字符串,默认为UTF-8编码
也可以存储为UTF-16BE或UTF-16LE
没有固定的长度限制(除了整个数据库的大小限制)
VARCHAR(N)中的长度限制仅作为文档说明,不强制执行
3.4 BLOB类型
CREATE TABLE files (file_id INTEGER PRIMARY KEY,file_name TEXT,file_data BLOB
);
注意事项:
原样存储二进制数据
适用于图像、音频、视频、加密数据等任何二进制内容
不进行任何编码或转换
没有大小限制(除了数据库大小限制)
3.5 NULL类型
CREATE TABLE users (user_id INTEGER PRIMARY KEY,middle_name TEXT DEFAULT NULL
);
注意事项:
表示缺少值
与其他数据库的NULL类似
NULL是一个特殊值,不等于零、空字符串或任何其他值
3.6 NUMERIC类型
CREATE TABLE financial (amount NUMERIC,tax DECIMAL(10,2),is_completed BOOLEAN,transaction_date DATE
);
注意事项:
可以存储为INTEGER、REAL或TEXT,具体取决于值
整数值优先存储为INTEGER
非整数数值存储为REAL
不符合数值格式的值存储为TEXT
4 特殊类型和类型转换
4.1 BOOLEAN
SQLite没有专门的布尔类型,通常用以下方式表示:
CREATE TABLE settings (feature_enabled BOOLEAN -- 实际存储为INTEGER: 0(false)或1(true)
);
注意事项:
存储为INTEGER: 0(false)或1(true)
在查询中,所有非0值和非NULL值都被视为true
4.2 DATE, DATETIME, TIMESTAMP
SQLite没有专门的日期或时间类型,通常以以下方式存储:
CREATE TABLE events (event_date DATE, -- 实际上是TEXT、REAL或INTEGERcreated_at TIMESTAMP, -- 实际上是TEXT、REAL或INTEGERmeeting_time DATETIME -- 实际上是TEXT、REAL或INTEGER
);
常见日期时间存储格式:
TEXT格式(推荐)- 如 ‘2023-05-15 15:30:00’
- ISO8601格式: ‘YYYY-MM-DD HH:MM:SS.SSS’
- 最便于人类阅读和理解
INTEGER格式 - Unix时间戳(自1970-01-01 00:00:00 UTC以来的秒数)
- 适合于日期比较和计算
REAL格式 - Julian日期格式(自公元前4714年起的天数)
- 可以精确到毫秒级别
SQLite提供内置日期函数处理这些格式:
date()
、time()
、datetime()
strftime()
julianday()
4.3 DECIMAL和精确数值
SQLite没有专门的DECIMAL或MONEY类型:
CREATE TABLE financial (price DECIMAL(10,2) -- 实际上是NUMERIC亲和性
);
对于需要精确计算的财务数据,有两种方案:
-
整数存储:将金额乘以100或10000存储为INTEGER
-- 存储$123.45为12345 INSERT INTO financial(price_cents) VALUES (12345); -- 查询时除以100 SELECT price_cents/100.0 AS price FROM financial;
-
TEXT存储:将精确小数存储为TEXT,需要计算时转换
5 类型转换和兼容性
5.2 显式类型转换
-- INTEGER转换
SELECT CAST('123' AS INTEGER); -- 返回123
SELECT CAST(123.45 AS INTEGER); -- 返回123 (截断)
-- REAL转换
SELECT CAST('123.45' AS REAL); -- 返回123.45
SELECT CAST(123 AS REAL); -- 返回123.0
-- TEXT转换
SELECT CAST(123 AS TEXT); -- 返回'123'
SELECT CAST(123.45 AS TEXT); -- 返回'123.45'
5.2 隐式类型转换规则
SQLite会根据上下文自动转换类型:
-
数值上下文中的TEXT
SELECT '123' + 456; -- 579 (TEXT转为INTEGER) SELECT '123.45' + 1; -- 124.45 (TEXT转为REAL)
-
TEXT上下文中的数值
SELECT 123 || 'abc'; -- '123abc' (INTEGER转为TEXT) SELECT 123.45 || 'x'; -- '123.45x' (REAL转为TEXT)
-
比较操作中的混合类型
SELECT 123 = '123'; -- 1 (true,比较前进行转换)
5.3 类型灵活性示例
CREATE TABLE flexible(x);
INSERT INTO flexible VALUES(NULL),(42),(3.14159),('hello'),(x'ABCD'); -- BLOB值
SELECT typeof(x), x FROM flexible;
结果:
typeof(x) x
--------- ------
NULL NULL
INTEGER 42
REAL 3.14159
TEXT hello
BLOB ABCD
6 数据类型的实际应用示例
6.1 主键和ROWID
-- 使用INTEGER PRIMARY KEY (推荐)
CREATE TABLE users (user_id INTEGER PRIMARY KEY, -- 与内部ROWID关联username TEXT UNIQUE
);
-- 隐式ROWID
CREATE TABLE messages (content TEXT-- 自动创建一个隐藏的ROWID列
);
-- 显式禁用ROWID
CREATE TABLE settings (key TEXT PRIMARY KEY,value TEXT
) WITHOUT ROWID; -- 节省空间,但不自动生成ID
6.2 处理二进制数据(BLOB)
-- 存储图像文件
CREATE TABLE images (image_id INTEGER PRIMARY KEY,name TEXT,data BLOB, -- 存储二进制图像数据mime_type TEXT
);
-- C#代码示例
// 读取图像到SQLite
byte[] imageData = File.ReadAllBytes("image.jpg");
using (var command = new SQLiteCommand(connection)) {command.CommandText = "INSERT INTO images(name, data, mime_type) VALUES (@name, @data, @mime)";command.Parameters.AddWithValue("@name", "sample.jpg");command.Parameters.AddWithValue("@data", imageData);command.Parameters.AddWithValue("@mime", "image/jpeg");command.ExecuteNonQuery();
}
6.3 存储和查询JSON数据
-- 创建包含JSON的表
CREATE TABLE products (product_id INTEGER PRIMARY KEY,name TEXT,attributes TEXT -- 存储JSON数据
);
-- 插入JSON数据
INSERT INTO products(name, attributes)
VALUES ('Smartphone', '{"color":"black","memory":"128GB","camera":"12MP"}');
-- 使用JSON函数查询(SQLite 3.9.0+)
SELECT name, json_extract(attributes, '$.color') AS color,json_extract(attributes, '$.memory') AS memory
FROM products;
-- 使用JSON路径操作符(SQLite 3.38.0+)
SELECT name,attributes->>'$.color' AS color,attributes->>'$.memory' AS memory
FROM products;
6.4 日期时间处理
-- 创建日期时间表
CREATE TABLE events (event_id INTEGER PRIMARY KEY,title TEXT,event_date TEXT, -- ISO格式日期created_at TEXT DEFAULT (datetime('now'))
);
-- 插入日期
INSERT INTO events(title, event_date)
VALUES ('Conference', '2023-12-15 09:00:00');
-- 日期计算和过滤
SELECT title, event_date
FROM events
WHERE date(event_date) > date('now');
-- 日期格式化
SELECT title, strftime('%Y-%m-%d', event_date) AS date_only,strftime('%H:%M', event_date) AS time_only
FROM events;
-- 日期差值计算(天数)
SELECT title,julianday('now') - julianday(event_date) AS days_diff
FROM events;
6.5 高效存储大表的考虑
-- 为大表选择高效数据类型
CREATE TABLE log_entries (id INTEGER PRIMARY KEY, -- 比BIGINT更节省空间timestamp INTEGER, -- Unix时间戳比ISO日期字符串更紧凑level TINYINT, -- 使用更小的整数类型(虽然存储还是INTEGER)message TEXT -- 可变长度字符串
);
-- 索引对类型的影响
CREATE INDEX idx_timestamp ON log_entries(timestamp);
-- 整数索引通常比文本索引更高效
7 数据类型的最佳实践
-
明确指定类型
-- 推荐 CREATE TABLE users (id INTEGER PRIMARY KEY,name TEXT NOT NULL,age INTEGER,score REAL ); -- 不推荐 CREATE TABLE users (id,name,age,score );
-
合理使用INTEGER PRIMARY KEY
-- 推荐 CREATE TABLE categories (category_id INTEGER PRIMARY KEY,name TEXT ); -- 不推荐对常用ID列使用TEXT类型 CREATE TABLE categories (category_id TEXT PRIMARY KEY, -- 更慢,更占空间name TEXT );
-
日期时间存储策略
-- 推荐(可读性好) CREATE TABLE appointments (appointment_date TEXT DEFAULT (datetime('now', 'localtime')) ); -- 推荐(计算效率高) CREATE TABLE logs (timestamp INTEGER DEFAULT (strftime('%s', 'now')) );
-
JSON存储与结构化数据的权衡
-- 少量属性,经常作为整体访问:使用JSON CREATE TABLE user_preferences (user_id INTEGER PRIMARY KEY,settings TEXT -- JSON数据 ); -- 频繁查询特定字段:使用结构化表 CREATE TABLE user_preferences_structured (user_id INTEGER PRIMARY KEY,theme TEXT,notifications BOOLEAN,language TEXT );
-
使用约束增强类型安全
CREATE TABLE employees (id INTEGER PRIMARY KEY,name TEXT NOT NULL,email TEXT UNIQUE CHECK(length(email) > 3 AND email LIKE '%@%'),salary REAL CHECK(salary >= 0),department_id INTEGER REFERENCES departments(id) );
8 SQLite类型系统的优缺点
8.1 优点
灵活性:可以存储任何类型的数据到任何列
简单性:不需要像其他数据库那样处理复杂的类型系统
兼容性:容易从其他系统导入数据,不会遇到严格类型不匹配问题
紧凑存储:值按实际需要的空间存储,而不是预分配固定大小
8.2 缺点
类型安全性较低:没有严格的类型检查,可能导致数据一致性问题
隐式转换可能导致意外行为:在操作中类型可能自动转换
与其他SQL数据库不完全兼容:迁移代码时需要注意类型差异
缺少专门的DECIMAL/金融类型:需要应用层面处理精确计算
9 总结
SQLite的数据类型系统虽然简单,但非常灵活且强大:
它提供5种基本存储类型:NULL, INTEGER, REAL, TEXT, BLOB
使用类型亲和性机制来尝试转换数据到合适的存储类型
不强制执行类型约束,但通过CHECK约束可以实现类型安全
灵活性使其非常容易使用,但需要在应用层面确保数据一致性
相比其他关系型数据库,SQLite的类型系统更加灵活,但也需要开发者更加谨慎地使用,确保数据的一致性和完整性。特别是在处理财务数据、精确计算和日期时间时,需要采取适当的存储策略。以上就是SQLite数据类型的全部内容啦,期待我们下期的相遇,下期将介绍SQLite的函数以及如何使用SQLite函数。