sqlite3简介
sqlite3是一款轻量级的、基于文件的开源关系型数据库引擎,由 d. richard hipp 于 2000 年首次发布。它遵循 sql 标准,但与传统的数据库系统不同,sqlite 并不运行在独立的服务器进程中,而是作为一个嵌入式数据库引擎直接集成到应用程序中。其所有的数据结构(包括表、索引、事务日志等)都保存在一个单一的 .db
文件中。
sqlite 的设计理念是“零配置、开箱即用”,开发者只需将其动态库链接进应用程序,就可以直接进行数据库操作,无需安装数据库服务或进行网络配置。
sqlite3 是 sqlite 的第三个主要版本,相较前代有更强的兼容性和更完整的 sql 支持,是目前最常用的版本。
sqlite3的特点
- 轻量嵌入式设计
sqlite3 不依赖服务器进程,仅作为应用的一部分存在;编译后的库小于 1mb,运行开销极低。
- 单文件存储结构
所有数据库内容都保存在一个磁盘文件中,便于复制、迁移和版本控制。
- 跨平台支持广泛
可以在 linux、windows、macos、android、ios 等操作系统中运行,源代码可编译到几乎所有主流平台。
- 兼容标准 sql92
尽管体积小,但 sqlite3 支持大部分标准 sql 语法,如事务、子查询、视图、触发器、聚合函数等。
- 零配置,无需安装
无需安装或初始化数据库,只要程序能访问数据库文件就可以使用。
- 事务完整性(acid)支持
sqlite3 保证事务的原子性、一致性、隔离性和持久性,适用于数据完整性要求较高的应用。
sqlite3的适用场景
sqlite3 由于其嵌入式、便携、小巧的特性,特别适用于以下场景:
- 移动应用开发(android/ios)
sqlite3 是 android 系统默认数据库,适合存储用户数据、缓存内容、离线功能等。
- 嵌入式系统 / iot 设备
如智能电视、车载系统、传感器节点等设备内存和性能有限,sqlite 是轻量数据存储的理想方案。
- 桌面软件
常用于办公类软件(如记事本、财务管理工具)中提供本地数据存储功能。
- 浏览器或前端环境
web 应用中的 indexeddb/localstorage 常借助 sqlite 作为底层数据库。
- 单用户或低并发系统
适合使用场景为单人或单线程访问,例如个人记账软件、本地日志记录系统等。
- 快速原型开发和测试
因为免安装、部署简单,sqlite 常被用于开发早期快速迭代和测试环境中。
- 嵌套系统中的缓存数据库
可作为大型数据库系统的本地缓存,提升访问性能,降低服务器负载。
sqlite 命令行工具(sqlite3 shell) 中的内置命令
命令 | 作用说明 |
---|---|
.open filename.db | 打开或创建一个 sqlite 数据库文件 |
.tables | 列出当前数据库中的所有表 |
.schema [table] | 查看某个表或所有表的建表语句(ddl) |
.headers on/off | 开启或关闭结果显示中的列标题 |
.read filename.sql | 执行指定的 sql 文件内容 |
.exit / .quit | 退出 sqlite 命令行 |
.databases | 查看当前连接的数据库文件 |
.nullvalue null_replacement | 设置 null 显示为什么字符串 |
.output filename.txt | 将查询结果输出到文件 |
基本操作语句
1.打开/创建数据库文件
sqlite 使用命令行或程序语言(如 python、c 等)调用 sqlite 引擎来打开或创建数据库文件。文件不存在时会自动创建。
sqlite3 mydatabase.db
该命令会在当前目录中创建一个名为 mydatabase.db
的数据库文件(如果尚不存在),并进入 sqlite 的交互式终端。你可以在里面执行 sql 命令。
2. 查看数据库中所有表
select name from sqlite_master where type='table';
或者使用 sqlite 命令行工具提供的快捷命令:
.tables
3. 查看表结构(pragma 语句)
pragma table_info(table_name);
示例:
pragma table_info(users);
cid | name | type | notnull | dflt_value | pk ----+-------+---------+---------+------------+---- 0 | id | integer | 0 | null | 1 1 | name | text | 0 | null | 0 2 | age | integer | 0 | null | 0
表相关操作
1. 创建表(create table
)
create table table_name ( column1 datatype [constraints], column2 datatype [constraints], ... );
用于定义一个新的数据表,并指定字段名、数据类型和约束(如主键、非空等)。
create table users ( id integer primary key, name text not null, age integer );
补充:查看某个表的建表语句. schema 表名
sqlite> .schema users create table users ( id integer primary key, name text not null, age integer );
2. 修改表结构(alter table
)
sqlite 支持的 alter table
功能比较有限,主要包括:
#修改表名 alter table table_name rename to new_table_name; #新增列 alter table table_name add column column_def;
示例:添加一个 email 字段
alter table users add column email text; sqlite> .schema users create table users ( id integer primary key, name text not null, age integer, email text );
你会发现 email
字段已经添加在表结构末尾。注意:sqlite 不支持删除列或修改列类型。
3. 删除表(drop table
)
drop table [if exists] table_name;
drop table if exists users;
4. 复制表结构与数据
sqlite 没有 create table ... like
语法,可以用以下方式复制结构和数据:
create table new_table as select * from old_table;
如果只想复制结构(不含数据):
create table new_table as select * from old_table where 0;
数据操作语句
1. 插入数据(insert into
)
insert into table_name (column1, column2, ...) values (value1, value2, ...);
也可以省略列名(前提是所有列都有值):
insert into table_name values (value1, value2, ...);
示例:
insert info uesrs (id, name, age, email) values (1, "alice", 25, "a@.com"); sqlite> select * from users; id | name | age | email ---+-------+-----+-------------------- 1 | alice | 25 | a@.com
2. 更新数据(update
)
update table_name set column1 = value1, column2 = value2, ... where condition;
示例:
update users set age = 26 whrer id = 1; sqlite> select * from users; id | name | age | email ---+-------+-----+-------------------- 1 | alice | 26 | a@.com
3. 删除数据(delete
)
delete from table_name where condition; 注意:如果不加 where,会删除整张表的数据
示例:
sqlite> select * from users; id | name | age | email ---+-------+-----+-------------------- 1 | alice | 26 | a@.com delete from users where id = 1; sqlite> select * from users; -- 空表,无结果
4. 查询数据(select
)
select column1, column2, ... from table_name [where ...] [order by ...] [limit ...];
select *
表示查询所有列。
查询进阶
1. 条件筛选(where
)
select column1, column2 from table_name where condition;
常用操作符包括:=
, !=
, >
, <
, >=
, <=
, like
, in
, between
, is null
等。
示例:
select * from users where age > 25; id | name | age | email ---+-------+-----+--------------------- 2 | bob | 30 | bob@example.com 3 | carol | 28 | carol@example.com
2. 排序(order by
)
select * from table_name order by column [asc|desc];
示例:
select * from users order by age desc; id | name | age | email ---+-------+-----+--------------------- 2 | bob | 30 | bob@example.com 3 | carol | 28 | carol@example.com 1 | alice | 25 | alice@example.com
3. 分组与过滤(group by
+ having
)
select group_column, aggregate_function(...) from table_name group by group_column [having condition];
示例:
select age, count(*) from users group by age having count(*) > 1; 假设有两名用户都 30 岁 age | count(*) ----+---------- 30 | 2
4. 多表连接(join
)
select columns from table1 join table2 on table1.column = table2.column;
示例:
表users id | name | age | email ---+-------+-----+--------------------- 2 | bob | 30 | bob@example.com 3 | carol | 28 | carol@example.com 1 | alice | 25 | alice@example.com 表orders user_id | amount --------+-------- 2 | 100 3 | 150 select users.name, orders.amount from users join orders on users.id = orders.user_id; -- 输出: name | amount ------+-------- bob | 100 carol | 150
5. 子查询与嵌套查询
select * from table where column in (select ... from ... where ...);
示例:
select name from users where id in (select user_id from orders where amount > 100); 输出: name ----- carol
6. 分页查询(limit / offset
)
select * from table_name limit 限制行数 offset 起始行偏移量; 指令说明 limit:限制最多返回多少行结果。 offset:跳过前面多少行数据再开始返回(可选)。
例如在一个页面中只显示 10 条数据,就可以:
select * from users order by id limit 10 offset 0; -- 第1页 select * from users order by id limit 10 offset 10; -- 第2页 select * from users order by id limit 10 offset 20; -- 第3页
或者用更常见的公式:
limit 每页条数 offset (页码 - 1) * 每页条数
示例:
原始数据为: id | name | age ---+-------+----- 1 | alice | 25 2 | bob | 30 3 | carol | 28 select * from users order by id limit 2 offset 1; 按 id 排序后,跳过第1条数据,从第2条开始取,最多取2条。 执行结果: id | name | age ---+-------+----- 2 | bob | 30 3 | carol | 28
索引与性能
1.sqlite3中的索引是什么?
在 sqlite 中,索引是一种数据库对象,它的作用类似于书本的目录,可以加快查询特定数据的速度。索引会为一个或多个列生成一个排序的数据结构(通常是 b-tree),从而使查询更快。
2.索引的特性?
加速查询(尤其是 where、join、order by 等)
当你查询某张表时:
select * from users where age > 25;
如果 age
上有索引,sqlite 会用索引快速定位符合条件的数据,而不用全表扫描。
提升排序效率
select * from users order by name;
如果 name
列已建索引,排序可以直接利用索引顺序完成,而无需临时排序。
加速多表连接(join)
select * from users join orders on users.id = orders.user_id;
如果 orders.user_id
建了索引,那么连接时匹配效率会更高。
不适用于频繁变动的字段
索引虽然能加速查询,但会减慢 insert
、update
、delete
的性能,因为每次数据改动,索引也要同步更新。
3. 创建索引(create index
)
为单列创建索引
create [unique] index index_name on table_name(column_name); unique 表示不允许重复值(可选)。
示例:
create index idx_users_age on users(age); #查看是否命中索引 explain query plan select * from users where age > 25; #输出 search table users using index idx_users_age (age>?) 说明查询使用了你创建的索引。
为多列创建联合索引
create index index_name on table_name(column1, column2, ...);
适用于查询中使用多个字段组合的情况。
遵守“最左前缀原则”
示例:
select * from users where name = 'alice' and age = 25; #查看是否命中索引 explain query plan select * from users where name = 'alice' and age = 25; #输出 search table users using index idx_users_name_age (name=? and age=?)
最左前缀原则: 复合索引只有在查询中使用了从左到右的“最前面的列”时,sqlite 才会使用该索引来优化查询。
示例:
id | name | age ---+-------+----- 1 | alice | 25 2 | bob | 30 3 | carol | 28 #创建复合索引 create index idx_name_age on users(name, age);
分别执行以下查询并查看是否命中索引
①使用 name(最左列),可以命中索引
explain query plan select * from users where name = 'alice'; search table users using index idx_name_age (name=?)
②使用 name + age(最左列 + 第二列),仍命中索引
explain query plan select * from users where name = 'alice' and age = 30; search table users using index idx_name_age (name=? and age=?)
③只使用 age,不命中索引
explain query plan select * from users where age = 30; scan table users
④使用 age + name(第二列 + 最左列),仍命中索引,顺序不影响
explain query plan select * from users where age = 30 and name = 'alice'; search table users using index idx_name_age (age=? and name=?)
注意:复合索引 idx_name_age(name, age)
是一棵按 name
排序、再按 age
排序的 b 树结构。查询必须从最左的列开始匹配,否则无法用上这个索引。
4. 删除索引(drop index
)
drop index [if exists] index_name;
事务控制
1. 开始事务(begin
)
begin;
- 用于开始一个事务。在事务开始后,所有的操作(如
insert
、update
、delete
)都将在这个事务中进行。 - 如果事务内的操作没有出现错误,事务可以被提交(
commit
)。如果出错,可以回滚(rollback
)整个事务。
2. 提交事务(commit
)
commit;
提交当前事务所做的所有更改。这会将事务中所有修改的数据写入数据库并使它们永久生效。
示例:提交事务
begin; insert into users (name, age, city) values ('eve', 40, 'chengdu'); update users set age = 45 where name = 'alice'; commit;
3. 回滚事务(rollback
)
rollback;
如果在事务中执行某些操作时发生错误,可以使用 rollback
来撤销所有在当前事务中的操作,恢复到事务开始前的状态。
示例:回滚事务
begin; insert into users (name, age, city) values ('eve', 40, 'chengdu'); update users set age = 45 where name = 'alice'; -- 假设此时发生了错误,我们决定回滚事务 rollback;
事务回滚后,eve
和 alice
的更新都将被撤销,users
表中的数据保持不变。
4. 自动提交模式
- 在默认情况下,sqlite 在每个独立的 sql 语句后自动提交。也就是说,每次执行一条语句时,sqlite 会自动把它作为一个单独的事务提交。
- 为了防止自动提交,可以显式地使用
begin
开始事务,直到使用commit
或rollback
。
5. 提交或回滚事务的应用场景
- 批量操作: 比如一次性插入大量数据,使用事务能够保证所有数据同时插入成功,避免数据不一致。
- 处理失败的操作: 在多步操作中,如果中途某一步失败,
rollback
可以保证整个操作的原子性。
事务控制的典型应用场景:
假设有一个转账操作,其中两个表分别是 accounts
(账户余额)和 transactions
(交易记录),我们需要确保转账操作成功或者完全回滚。
try { executeorthrow(db, "begin;"); executeorthrow(db, "update accounts set balance = balance - 100 where account_id = 'a001';"); // 故意出错:列名 balxxx 不存在 executeorthrow(db, "update accounts set balxxx = balance + 100 where account_id = 'a002';"); executeorthrow(db, "insert into transactions (from_account, to_account, amount) values ('a001', 'a002', 100);"); //没问题就提交 executeorthrow(db, "commit;"); std::cout << "transaction committed.\n"; } catch (const std::exception& ex) { std::cerr << ex.what() << "\n"; //出错回滚 sqlite3_exec(db, "rollback;", nullptr, nullptr, nullptr); std::cout << "transaction rolled back.\n"; }
视图与临时表
视图(view)
视图是 虚拟的表,本质上是对一个 select
查询结果的封装,它本身不存储数据,而是每次访问时执行背后的查询语句。它的存在意义主要在于以下几点:
1. 简化复杂查询
当你有一些经常要执行的复杂 join
、子查询
或 聚合查询
时,把它们写进视图,可以像操作普通表一样简单调用:
-- 查询最近30天订单金额前10的用户 select * from top_users_last_30_days;
而不用每次都写长查询。
一个视图可以作为多个后续查询的中间层,避免重复 join
和 group by
逻辑,提高可复用性和效率。
2. 增强可读性与可维护性
把复杂查询逻辑隐藏到视图中后,业务 sql 更清晰:
-- 直接查视图 select * from user_purchases_summary where total_spent > 1000;
而不是写重复的 sql 逻辑多处维护。
3.提高安全性
你可以只授予用户对视图的访问权限,而非对底层表的权限,从而达到权限隔离的效果。
创建视图:
create [temp | temporary] view view_name as select ...; view_name:视图名称 select ...:视图对应的查询语句 temp:可选,创建临时视图,仅在当前连接中可见
示例:创建一个只读用户信息视图
create view active_users as select id, name, email from users where status = 'active';
你可以像查询普通表一样使用视图:
select * from active_users;
假设 users 表如下: | id | name | email | status | | -- | ----- | --------------------------------------- | -------- | | 1 | alice | [alice@mail.com](mailto:alice@mail.com) | active | | 2 | bob | [bob@mail.com](mailto:bob@mail.com) | inactive | | 3 | carol | [carol@mail.com](mailto:carol@mail.com) | active | 那么 active_users 视图返回: | id | name | email | | -- | ----- | --------------------------------------- | | 1 | alice | [alice@mail.com](mailto:alice@mail.com) | | 3 | carol | [carol@mail.com](mailto:carol@mail.com) |
注意:如果你没有显式使用 temp
或 temporary
关键字,那么你创建的视图就是持久视图
删除视图:
drop view active_users;
临时表(temp table)
临时表是只在当前数据库连接中可见的表,连接关闭后自动销毁。它们的主要目的是用于临时数据的存储与处理,不污染正式的数据表结构。它的存在意义主要在于以下几点:
1. 存放中间结果,简化复杂操作
在处理多步 sql 逻辑(如报表、分析、批量更新)时,临时表可以存放中间结果,让后续查询更清晰:
create temp table temp_summary as select user_id, sum(amount) as total from orders group by user_id;
然后你可以继续基于 temp_summary
做筛选、排序等操作。
2. 提高性能,避免重复计算
有些数据在多个地方会用到,而计算代价较高(例如聚合、大量连接),你可以先写入临时表,然后反复查询:
-- 避免重复 join 操作,提高整体查询速度 select * from temp_result where score > 80;
3.并发安全,每个连接互不干扰
sqlite 的临时表是连接隔离的:
- 多个连接可以使用同名临时表
- 它们之间的数据互不影响
这使得临时表非常适合多线程/多连接场景下的临时数据隔离处理
总结:临时表的作用是为当前连接提供一个安全、高效、隔离的临时数据空间,专注于中间处理、性能优化与调试而不影响正式数据库结构与数据。
创建临时表:
create temp table temp_table_name ( column1 type, column2 type, ... );
- 临时表只在当前数据库连接中有效
- 连接关闭后自动删除
- 临时表与视图不同,它是真实存储数据的表,只是生命周期短
示例:创建并使用一个临时表
create temp table temp_orders ( id integer, product text, quantity integer ); insert into temp_orders values (1, 'book', 2); insert into temp_orders values (2, 'pen', 5); select * from temp_orders; 查询结果(临时表内容): | id | product | quantity | | -- | ------- | -------- | | 1 | book | 2 | | 2 | pen | 5 |
视图 vs 临时表
项目 | 视图(view) | 临时表(temp table) |
---|---|---|
本质 | 基于 select 的虚拟表,不存储数据 | 存储真实数据的临时性表 |
是否持久存在 | 是(除非使用 temp 创建) | 否,只在当前连接中存在,断开即销毁 |
数据存储 | 不存储数据,每次使用实时查询底层表 | 存储数据,像普通表一样支持增删改查 |
创建语法 | create [temp] view view_name as ... | create temp table table_name (...) |
删除方式 | drop view view_name; | 自动销毁(连接关闭)或手动 drop table |
生命周期 | 持久(数据库文件的一部分) | 连接会话级,连接断开即清除 |
可更新性 | 只读(除非符合可更新视图条件) | 可读可写,完全等同于普通表 |
典型用途 | 封装复杂查询、简化 sql、权限控制 | 存储中间数据、性能优化、测试临时数据 |
是否支持索引 | 否(依赖底层表索引) | 是(可为临时表单独建索引) |
作用范围 | 所有连接(持久视图)或当前连接(temp) | 当前连接 |
是否写入磁盘 | 是(除 temp view ) | 否(仅存储在内存或临时磁盘空间) |
常用函数与表达式
字符串处理函数
函数名 | 功能说明 | 示例 sql | 返回结果 |
---|---|---|---|
length(x) | 返回字符串 x 的字符长度 | select length('sqlite'); | 6 |
substr(x,y,z) | 提取 x 中从第 y 位开始的 z 个字符 | select substr('sqlite3', 2, 4); | 'qlit' |
lower(x) / upper(x) | 转换为小写 / 大写 | select upper('abc'); | 'abc' |
trim(x) | 去除前后空白字符 | select trim(' abc '); | 'abc' |
replace(x,y,z) | 将 x 中所有 y 替换为 z | select replace('hello', 'l', 'l'); | 'hello' |
instr(x, y) | 查找 y 在 x 中首次出现的位置(1 开始) | select instr('abcdef', 'cd'); | 3 |
printf(fmt, ...) | 格式化字符串,类似 c 的 printf | select printf('%.2f', 3.14159); | '3.14' |
hex(x) | 将字符串或 blob 转为十六进制表示 | select hex('abc'); | '616263' |
数值函数
函数名 | 功能说明 | 示例 sql | 返回结果 |
---|---|---|---|
abs(x) | 绝对值 | select abs(-10); | 10 |
round(x[,y]) | 四舍五入到 y 位小数,默认 0 | select round(3.14159, 2); | 3.14 |
random() | 返回一个大范围随机整数 | select random(); | 随机整数 |
random() % n | 控制随机值范围(常配合 abs 使用) | select abs(random() % 10); | 0 ~ 9 |
typeof(x) | 返回数据类型(如 integer, text) | select typeof(3.14); | 'real' |
coalesce(x, y, ...) | 返回第一个非 null 的值 | select coalesce(null, '', 'abc'); | '' |
nullif(x, y) | 如果 x == y ,返回 null,否则返回 x | select nullif(5, 5); | null |
sign(x) | 不内置,可用 case 模拟,判断数正负 | select case when x > 0 then 1 when x < 0 then -1 else 0 end | -1 / 0 / 1 |
日期与时间函数
函数名 | 功能说明 | 示例 sql | 返回结果 |
---|---|---|---|
date('now') | 当前日期 | select date('now'); | 2025-05-08 |
datetime('now') | 当前日期时间 | select datetime('now'); | 2025-05-08 13:50:00 |
time('now') | 当前时间(不含日期) | select time('now'); | 13:50:00 |
strftime('%y-%m-%d', 'now') | 日期格式化输出 | select strftime('%y-%m-%d', 'now'); | 2025-05-08 |
strftime('%s', 'now') | 当前时间戳(秒) | select strftime('%s', 'now'); | unix 时间戳 |
strftime('%w', 'now') | 星期几(0 表示周日) | select strftime('%w', 'now'); | 4 (周四) |
julianday('now') | 当前日期的儒略日表示法(浮点) | select julianday('now'); | 2460451.08 |
datetime('now', '+7 days') | 时间加减(也支持 -2 hours , +1 month 等) | select datetime('now', '-1 day'); | 昨天的时间 |
聚合函数
函数名 | 功能说明 | 示例 sql | 返回结果 |
---|---|---|---|
count(x) | 非 null 值数量 | select count(name) from users; | 42 (示例) |
count(*) | 所有行数量 | select count(*) from users; | 100 |
sum(x) | 求和 | select sum(price) from orders; | 2300.50 |
avg(x) | 平均值 | select avg(score) from exams; | 82.5 |
max(x) | 最大值 | select max(age) from people; | 64 |
min(x) | 最小值 | select min(age) from people; | 18 |
条件表达式
表达式 | 功能说明 | 示例 sql | 返回结果 |
---|---|---|---|
case when ... then ... | 条件判断(if-else) | select case when score > 90 then '优' when score > 60 then '中' else '差' end | '优' / '中' / '差' |
case x when a then ... | 值匹配(更紧凑形式) | select case grade when 'a' then 4 when 'b' then 3 else 0 end | 4 / 3 / 0 |
coalesce(x, y, z) | 返回第一个非 null 值 | select coalesce(null, null, 'hello'); | 'hello' |
nullif(x, y) | 如果 x == y 则返回 null,否则返回 x | select nullif(5, 5); | null |
ifnull(x, y) | 如果 x 是 null,则返回 y,否则返回 x(别名) | select ifnull(null, 'default'); | 'default' |
示例:
下面是一个综合性 sql 示例,它模拟了一个电商订单分析的场景
建表:
-- 创建客户表 create table customers ( id integer primary key, -- 客户 id,主键 name text, -- 客户名称 email text -- 客户邮箱 ); -- 创建订单表 create table orders ( id integer primary key, -- 订单 id,主键 customer_id integer, -- 关联客户 id product_name text, -- 商品名称 price real, -- 商品单价 quantity integer, -- 购买数量 order_date text, -- 下单时间(格式:yyyy-mm-dd hh:mm:ss) foreign key (customer_id) references customers(id) -- 外键关联客户表 );
插入数据:
-- 插入客户 insert into customers (id, name, email) values (1, 'alice', 'alice@example.com'), (2, 'bob', 'bob@example.net'), (3, 'charlie', 'charlie@example.org'); -- 插入订单 insert into orders (customer_id, product_name, price, quantity, order_date) values (1, 'laptop', 899.99, 1, '2025-01-15 10:00:00'), (1, 'mouse', 19.99, 2, '2025-02-10 12:30:00'), (2, 'keyboard', 49.99, 1, '2025-03-05 14:20:00'), (2, 'monitor', 199.99, 1, '2025-03-06 15:10:00'), (2, 'usb cable', 9.99, 3, '2025-04-01 09:00:00'), (3, 'desk chair', 129.99, 1, '2025-01-22 16:00:00');
sql
select c.name as customer_name, -- 客户名称 upper(substr(c.email, 1, instr(c.email, '@') - 1)) as email_user, -- 提取 email @ 前部分并转为大写 count(o.id) as total_orders, -- 订单总数 sum(o.price * o.quantity) as total_spent, -- 总消费金额 round(avg(o.price * o.quantity), 2) as avg_order_value, -- 平均订单金额(保留2位小数) max(o.order_date) as last_order_date, -- 最后一笔订单的时间 strftime('%y-%m', o.order_date) as order_month, -- 订单月份(用于聚合) -- 消费金额区间分级:vip / gold / regular case when sum(o.price * o.quantity) > 1000 then 'vip' when sum(o.price * o.quantity) > 500 then 'gold' else 'regular' end as customer_level from customers c left join orders o on c.id = o.customer_id -- 关联订单表 where o.order_date >= date('now', '-6 months') -- 仅查询最近6个月的订单 group by c.id having total_orders > 0 -- 排除没有订单的客户 order by total_spent desc -- 按总消费金额降序排列 limit 10; -- 仅显示前10个客户
sqlite 专有特性
autoincrement 和 integer primary key
integer primary key
是 sqlite 中用于定义主键并且自动增长的特殊类型。- 如果你定义了某个列为
integer primary key
,当向表中插入一行数据时sqlite 会自动为该列赋值(自增),无需显式使用autoincrement
。 autoincrement
是一种“更严格”的版本,它会防止重复使用已删除的 id。
特性 | integer primary key | integer primary key autoincrement |
---|---|---|
自动增长 | 是 | 是 |
会复用已删除的 id? | 会 | 不会 |
是否推荐? | 推荐(性能更好) | 不推荐,除非必须保证唯一不复用 |
示例:
-- 普通自增主键 create table users ( id integer primary key, name text ); -- 带 autoincrement 的主键 create table logs ( id integer primary key autoincrement, message text );
without rowid 表
sqlite 默认使用一个隐藏的 rowid
来标识每一行。但你可以显式使用 without rowid
表来:
- 减少存储开销(适合复合主键场景)
- 提高某些查询性能(尤其当不需要 rowid 时)
示例:
-- 默认带有 rowid create table cities ( name text primary key, population integer ); -- 不使用 rowid create table cities_norowid ( name text primary key, population integer ) without rowid;
说明:without rowid
表要求必须有主键,且主键不可为 rowid
。
pragma 指令
pragma
是 sqlite 的一组特殊命令,用于查看或设置数据库的内部参数或行为。
指令 | 用途说明 | 示例 |
---|---|---|
pragma table_info(table_name) | 查看表结构(字段信息) | pragma table_info(users); |
pragma foreign_keys | 查看外键是否启用(1 为开启) | pragma foreign_keys; |
pragma foreign_keys = on; | 启用外键约束 | pragma foreign_keys = on; |
pragma database_list | 查看当前连接的数据库列表 | pragma database_list; |
pragma index_list(table_name) | 查看表上的索引列表 | pragma index_list(users); |
pragma cache_size | 设置或查看内存页缓存大小 | pragma cache_size = 2000; |
pragma journal_mode | 设置事务日志模式(如 wal) | pragma journal_mode = wal; |
pragma synchronous | 控制同步级别(性能 vs 安全) | pragma synchronous = normal; |
发表评论