SQLite 命令速查表 - SQLite 数据库常用命令大全

嵌入式数据库的选择其实很窄:需要零运维、单文件可搬、备份就是拷贝的时候,SQLite 几乎总是正确答案,代价是同一时刻只允许一个写者。这张表按连接与基础、表操作、数据操作、查询进阶、索引与约束、事务与锁、导入导出与工具、实用函数与 PRAGMA 分组,命令从建库建表一路排到事务、WAL 模式与 CSV 导入导出。判断依据是并发模型:如果写入来自多个进程或多个线程,PRAGMA journal_mode=WAL 加上合理的 busy_timeout 就是必选项;如果只是单机脚本,那么真正该做的是把类型和约束在表定义里定死,让错误在插入时就失败。什么时候翻它:给命令行工具加本地持久化、做数据迁移、跑一次性分析、或者把 CSV 快速灌进库里再查。与 Postgres 或 MySQL 的分界很明确——没有服务进程也就没有网络层,瓶颈通常出现在写入而非查询。

数据库·共 52 条命令·最后更新 2026-07-21
sqlitedatabasesql嵌入式数据库

典型使用场景

面向需要轻量本地存储的开发者:桌面与移动应用的内嵌数据、脚本与自动化任务、测试夹具、浏览器本地数据、服务端的中小规模只读配置。SQLite 零配置、无需服务端进程,一个文件就是一个库,拷走即迁移。本表覆盖三层内容:DML 与查询进阶(UPSERT、GROUP BY + HAVING、JOIN、聚合函数);索引与约束(唯一索引、外键、CHECK)——这是决定数据量上来后性能好坏的唯一手段;以及运维向的 `PRAGMA journal_mode=WAL`、`.dump` 备份、`VACUUM` 回收空间和 `integrity_check`。

数据库连接与基础 6

sqlite3 file.db
打开或创建 SQLite 数据库文件
.open file.db
在 sqlite3 命令行中打开数据库文件
.databases
列出所有已打开的数据库连接
.tables
列出当前数据库中的所有表
.quit
退出 sqlite3 命令行工具
.help
查看所有可用点命令的帮助信息

表操作 6

CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
创建表,定义列和约束
DROP TABLE IF EXISTS users;
删除表(如存在)
ALTER TABLE users ADD COLUMN email TEXT;
添加新列
CREATE TABLE backup AS SELECT * FROM users;
通过查询结果创建新表
CREATE TEMP TABLE temp_data (id INT);
创建临时表,会话结束后自动删除
.schema users
查看表的建表语句

数据操作 7

INSERT INTO users (name, age) VALUES ('Tom', 25);
插入单条记录
INSERT INTO users (name, age) VALUES ('Tom', 25), ('Jerry', 30);
批量插入多条记录
SELECT * FROM users;
查询所有记录
UPDATE users SET age = 26 WHERE name = 'Tom';
更新符合条件的记录
DELETE FROM users WHERE name = 'Tom';
删除符合条件的记录
REPLACE INTO users (id, name, age) VALUES (1, 'Tom', 26);
插入或替换(基于主键或唯一约束)
INSERT INTO users (id, name) VALUES (1, 'Tom') ON CONFLICT(id) DO UPDATE SET name = excluded.name;
UPSERT:冲突时更新,不冲突时插入

查询进阶 8

SELECT * FROM users WHERE age > 18;
WHERE 条件过滤
SELECT * FROM users ORDER BY age DESC, name ASC;
多字段排序
SELECT status, COUNT(*) FROM users GROUP BY status;
GROUP BY 分组统计
SELECT status, COUNT(*) FROM users GROUP BY status HAVING COUNT(*) > 5;
HAVING 过滤分组结果
SELECT * FROM users LIMIT 10 OFFSET 20;
分页:限制返回数量并跳过前 20 条
SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id;
INNER JOIN 关联查询
SELECT DISTINCT city FROM users;
去重查询
SELECT COUNT(*), AVG(age), MAX(age), MIN(age) FROM users;
聚合函数:计数、平均值、最大值、最小值

索引与约束 6

CREATE INDEX idx_users_name ON users(name);
创建索引加速查询
CREATE UNIQUE INDEX idx_users_email ON users(email);
创建唯一索引
DROP INDEX IF EXISTS idx_users_name;
删除索引
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, age INT DEFAULT 0);
定义列级约束:主键、唯一、非空、默认值
CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INT REFERENCES users(id));
定义外键约束
CREATE TABLE products (id INT, price REAL CHECK(price > 0));
CHECK 约束:限制值范围

事务与锁 7

BEGIN TRANSACTION;
开始事务
COMMIT;
提交事务,持久化所有更改
ROLLBACK;
回滚事务,撤销所有未提交的更改
SAVEPOINT sp1;
设置保存点,支持部分回滚
ROLLBACK TO sp1;
回滚到指定保存点
RELEASE SAVEPOINT sp1;
释放保存点
PRAGMA journal_mode=WAL;
设置 WAL 模式提升并发读写性能

导入导出与工具 6

.import --csv data.csv my_table
将 CSV 文件导入为表
.output dump.sql
将后续输出重定向到文件
.dump
导出整个数据库为 SQL 文本
.read dump.sql
执行 SQL 文件(导入备份)
VACUUM;
回收空闲空间,减小数据库文件体积
ANALYZE;
更新统计信息帮助查询优化器

实用函数与 PRAGMA 6

PRAGMA table_info(users);
查看表的列信息
PRAGMA index_list(users);
查看表的索引列表
PRAGMA integrity_check;
检查数据库完整性
SELECT datetime('now');
获取当前日期时间
SELECT strftime('%Y-%m-%d', 'now');
格式化日期输出
SELECT length('hello'), typeof(42), randomblob(16);
length/typeof/randomblob 实用函数

参数矩阵

参数作用示例
.open <file>打开或创建数据库文件sqlite3 file.db
.tables / .databases列出当前库的表 / 已打开的连接.tables
.schema <table>查看建表语句.schema users
CREATE TABLE ... PRIMARY KEY定义主键与列级约束CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, age INT DEFAULT 0);
REFERENCES users(id)外键约束CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INT REFERENCES users(id));
CHECK(price > 0)限制列的取值范围CREATE TABLE products (id INT, price REAL CHECK(price > 0));
ON CONFLICT DO UPDATEUPSERT:冲突更新、不冲突插入INSERT INTO users (id, name) VALUES (1, 'Tom') ON CONFLICT(id) DO UPDATE SET name = excluded.name;
REPLACE INTO按主键或唯一约束插入或整行替换REPLACE INTO users (id, name, age) VALUES (1, 'Tom', 26);
GROUP BY + HAVING分组统计后再过滤分组SELECT status, COUNT(*) FROM users GROUP BY status HAVING COUNT(*) > 5;
LIMIT / OFFSET分页:限制条数并跳过前若干条SELECT * FROM users LIMIT 10 OFFSET 20;
JOIN ... ON关联查询(INNER JOIN)SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id;
CREATE [UNIQUE] INDEX建索引 / 唯一索引以加速与去重CREATE UNIQUE INDEX idx_users_email ON users(email);
PRAGMA journal_mode=WAL切 WAL 模式提升并发读写性能PRAGMA journal_mode=WAL;
BEGIN / COMMIT / ROLLBACK事务边界控制BEGIN TRANSACTION;
SAVEPOINT / ROLLBACK TO保存点与部分回滚ROLLBACK TO sp1;
.import --csv把 CSV 导入为表.import --csv data.csv my_table
.dump / .read导出整库为 SQL / 执行 SQL 文件恢复.dump
VACUUM / ANALYZE回收空闲空间 / 更新统计信息VACUUM;
PRAGMA integrity_check检查数据库文件完整性PRAGMA integrity_check;

易错点与避坑指南

现象数据库文件越用越大,删掉大量数据后体积纹丝不动

原因删除只是把页标记为空闲,不会自动把文件缩回去。

处置执行 `VACUUM;` 回收空闲空间;该操作会重写整库,注意预留磁盘余量。

现象查询在数据量上来后越来越慢,执行计划里没有用上索引

原因统计信息陈旧,优化器按旧数据量做决策;或者查询条件与索引列不匹配。

处置先跑 `ANALYZE;` 更新统计信息,再用 `PRAGMA index_list(users)` 确认目标列上确实有索引。

现象写入时报 database is locked,或并发读多时频繁超时

原因默认回滚日志模式下读写互斥,长事务还会一直占着锁。

处置执行 `PRAGMA journal_mode=WAL;` 切换到 WAL;并把批量操作包进事务,用 `COMMIT` 尽早释放。

现象批量导入做了一半失败,数据处于半成品状态

原因多条语句没有事务包裹,前半段已提交无法回退。

处置用 `BEGIN TRANSACTION;` 开头,出错走 `ROLLBACK;`,成功走 `COMMIT;`;需要更细的粒度时用 `SAVEPOINT sp1;` 和 `ROLLBACK TO sp1;`。

现象按某个从别的 SQL 迁过来的语法写查询,直接报错

原因SQLite 支持大部分 SQL-92 标准,但不支持 RIGHT JOIN 和 FULL JOIN。

处置改写为 `LEFT JOIN`,或用子查询/`UNION` 的组合达到同样结果。

现象恢复备份时报语法错误,文件只恢复了一半

原因`.read` 逐条执行导出文件,文件里含有不支持的语句或编码不一致。

处置先 `PRAGMA integrity_check;` 确认库本身完好,再用 `sqlite3 new.db < dump.sql` 整文件重放,观察是否有报错行。

现象命令和 DDL 一起执行时看起来没生效

原因`.tables`、`.schema`、`.import`、`.output` 这类是 sqlite3 命令行专属的点命令,不能放进 SQL 脚本或代码字符串里交给数据库引擎执行。

处置在 sqlite3 交互 shell 中执行点命令,或在脚本文件里改用等价的 SQL 语句。

排障路径

  1. 1确认文件完整性

    PRAGMA integrity_check;

    输出 ok 表示文件结构完好;出现错误行则应先用 .dump 抢救数据再修复。

  2. 2查看表结构与实际建表语句

    .schema users

    建表语句里能看到约束与索引定义是否如设计预期。

  3. 3查看列信息与索引清单

    PRAGMA table_info(users); PRAGMA index_list(users);

    前者确认列类型与是否可空,后者确认查询条件列上是否已有索引。

  4. 4统计分组结果定位异常数据

    SELECT status, COUNT(*) FROM users GROUP BY status HAVING COUNT(*) > 5;

    输出可直接看出哪些分组数据异常集中,HAVING 在此过滤的是分组而非行。

  5. 5把整库导出为 SQL 做备份

    .output dump.sql && .dump

    先 .output 重定向再 .dump,生成的 dump.sql 即为可重放的备份文本。

  6. 6切到 WAL 并确认生效

    PRAGMA journal_mode=WAL; PRAGMA integrity_check;

    第一条应返回 wal,随后跑一次完整性检查确认切换后库仍可正常读写。

命令示例

先备份再改结构,出问题整库回退

.output dump.sql .dump .open file.db .read dump.sql

.output 把后续输出重定向到文件,紧接着 .dump 就把整个库写进 dump.sql。改表、加索引前先做这一步:SQLite 没有系统级快照,误删列只能靠这个文件恢复。恢复时对空库执行 .read 即可。

输出

dump.sql  // 数据库被导出为可重放的 SQL 文本

批量改数据放进事务,出错回滚

BEGIN TRANSACTION; UPDATE users SET age = age + 1 WHERE age < 18; SELECT COUNT(*) FROM users WHERE age = 18; COMMIT;

UPDATE/DELETE 少了 WHERE 就是全表覆盖。放进事务里先看 SELECT 结果再 COMMIT,确认影响行数符合预期;不符合就 ROLLBACK,数据库回到原状。

分组统计并过滤掉小样本

SELECT status, COUNT(*) FROM users GROUP BY status HAVING COUNT(*) > 1;

WHERE 在分组前过滤行,HAVING 在分组后过滤组。查「有两条以上记录的状态」必须用 HAVING——写在 WHERE 里只会把不满足的行剔掉,COUNT 结果仍是 1。

输出

status | COUNT(*)
active | 2

UPSERT:同一段脚本重复跑也不会产生重复行

INSERT INTO users (id, name) VALUES (1, 'Tom') ON CONFLICT(id) DO UPDATE SET name = excluded.name;

对比 REPLACE INTO:REPLACE 是「先删后插」,外键级联删除会连带删掉关联行;ON CONFLICT DO UPDATE 是原地更新,只动指定的列。写迁移脚本或导入脚本时用 UPSERT 比 REPLACE 安全得多。

排查「查询很慢」:看列、看索引、看执行计划

PRAGMA table_info(users); PRAGMA index_list(users); ANALYZE;

table_info 能确认列类型和默认值——很多「插不进去」其实是类型或约束问题;index_list 看索引是否真的建上;ANALYZE 更新统计信息让优化器选对索引。三条跑完,慢查询的原因基本就锁定在缺索引或缺统计信息上。

输出

cid | name | type | notnull | dflt_value | pk
0 | id | INTEGER | 0 | NULL | 1
1 | name | TEXT | 1 | NULL | 0
2 | age | INT | 0 | 0 | 0

保存点:长事务里只回滚其中一段

BEGIN TRANSACTION; SAVEPOINT sp1; DELETE FROM users WHERE name = 'Bob'; ROLLBACK TO sp1; RELEASE SAVEPOINT sp1; COMMIT;

DELETE 之后 SELECT COUNT(*) 仍是 3:ROLLBACK TO sp1 只撤销了保存点之后的操作,前面的工作全部保留。这是分批处理大量数据时「失败只丢一批」的最小单位。

常见坑与注意事项

  • UPDATE 或 DELETE 漏写 WHERE 会覆盖/删除全表数据。SQLite 没有系统快照,事后只能靠 .dump 备份恢复;执行前务必先用同条件 SELECT 数一遍。
  • REPLACE INTO 基于主键冲突时会先删后插,外键级联删除可能连带清掉关联表数据,且不可恢复;优先用 ON CONFLICT DO UPDATE。
  • SQLite 默认不开启外键约束(PRAGMA foreign_keys 为 0),建了 REFERENCES 也不会拦截脏数据;迁移脚本要在同一个连接里显式开启并复检。
  • 不开启 WAL 时并发写会互相阻塞并报 database is locked,长事务尤其明显;生产环境先 PRAGMA journal_mode=WAL,但注意它会生成 -wal/-shm 伴随文件,备份时不能只拷 .db。
  • .read dump.sql 往已有数据的库执行会直接追加并产生重复行,不报错;恢复必须针对空库进行。
  • .import --csv 依赖文件列顺序与表结构一致,CSV 列顺序一变数据就会静默错位;导入后先 SELECT 抽查几行。
  • UPDATE ... SET age = 25 赋值类型与列声明不一致时,SQLite 的动态类型可能把数字存成文本;用 PRAGMA table_info 核对类型,别只看值「看起来对不对」。
  • VACUUM 只能在没有活跃事务时执行,且会重写整个数据库文件,大库上执行会长时间锁库并需要约两倍磁盘空间;线上执行前先停写。

提示

  • SQLite 是零配置数据库,无需安装服务端进程
  • 使用 .dump 备份数据库,VACUUM 回收空间
  • PRAGMA journal_mode=WAL 可显著提升并发性能
  • SQLite 支持大部分 SQL-92 标准,但不支持 RIGHT/FULL JOIN
  • .import 命令支持 CSV 文件直接导入为表
  • 启用 WAL 后读写不互斥,但仍是单写者:多进程高频写入需靠 busy_timeout 等待,而不是靠重试。
  • 大表加索引前先用 EXPLAIN QUERY PLAN 看走没走上索引,凭直觉加索引常常只增大库不提速。
  • 整库备份用 .backup 或 .dump 而非直接复制 .db 文件,WAL 模式下直接拷贝可能拿到不一致的快照。

常见问题

REPLACE INTO 和 UPSERT 该怎么选?

REPLACE INTO `users` 是「先删后插」:命中主键或唯一约束时删除旧行再插入新行,触发删除与插入行为,外键级联也会跟着走,只适合确定要整行覆盖的场景。UPSERT 更精细:`INSERT INTO users (id, name) VALUES (1, 'Tom') ON CONFLICT(id) DO UPDATE SET name = excluded.name`,冲突时只更新指定列(用 excluded 引用新值),不冲突时正常插入,其余字段保持不变。需要保留原记录的部分字段就用 UPSERT。

怎么用 sqlite3 命令行做备份和恢复?

备份用 `.output dump.sql` 把输出重定向到文件,紧接着执行 `.dump`,整个库就导出成 SQL 文本了;恢复时用 `.read dump.sql` 执行它。想搬一批 CSV 进来用 `.import --csv data.csv my_table`,同样先 `.output` 再导也能导出成表。数据膨胀后跑一次 `VACUUM;` 回收空闲空间减小文件体积,`ANALYZE;` 更新统计信息帮助优化器选索引。怀疑文件损坏先跑 `PRAGMA integrity_check;`。

什么时候该给字段建索引,建错了会有什么代价?

给高频过滤、排序、关联的列建索引:`CREATE INDEX idx_users_name ON users(name)`;需要唯一性就用 `CREATE UNIQUE INDEX idx_users_email ON email`,它同时充当数据约束。代价是写入变慢——每次 INSERT/UPDATE 都要维护索引结构,还会占用磁盘空间,所以别给几乎不查询的列加。用 `PRAGMA index_list(users);` 确认当前有哪些索引,不需要的用 `DROP INDEX IF EXISTS idx_users_name;` 清掉。`CREATE TABLE backup AS SELECT * FROM users` 生成的新表不继承索引,需要重建。

WHERE 和 HAVING 有什么区别,怎么搭配 GROUP BY?

WHERE 在分组之前过滤原始行,只能用普通列,不能用聚合函数;HAVING 在分组聚合之后过滤分组结果,必须配合 GROUP BY 使用。典型统计写法:`SELECT status, COUNT(*) FROM users GROUP BY status HAVING COUNT(*) > 5`,只保留人数超过 5 的分组。如果两个条件都有,顺序是先 WHERE 缩小数据集、再 GROUP BY 聚合、最后 HAVING 筛分组,效率最高。多字段排序用 `ORDER BY age DESC, name ASC`。

多人同时写 SQLite 报 database is locked,怎么调优?

先把日志模式换成 WAL:`PRAGMA journal_mode=WAL;`,它允许读写并发,配合 `PRAGMA journal_mode=WAL` 提示里说的性能提升,是解决锁冲突的第一步。写操作务必包在事务里,`BEGIN TRANSACTION;` 后连续执行多条 INSERT 再 `COMMIT;`,可以避免每条语句单独加锁。需要局部回滚时用 `SAVEPOINT sp1;` 打点,出问题 `ROLLBACK TO sp1;`,不需要了 `RELEASE SAVEPOINT sp1;`,整体放弃用 `ROLLBACK;`。临时中间表用 `CREATE TEMP TABLE`,会话结束自动清理,不参与主库锁。

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。

由 巧匠 维护

公开更新于 2026年7月21日,内容持续校对官方文档。

联系我们

命令或描述有误?提交反馈、商务合作或产品建议都可发送邮件给我们。

联系我们