导出是命令行的工作,不是 SQL 语句
SQLite 没有 Postgres 那样的 COPY ... TO,也没有 MySQL 那样的 SELECT INTO OUTFILE。导出数据要在 sqlite3 命令行工具中完成,靠的是点命令:.mode、.headers、.output、.dump。掌握这四个命令,你就能从任何数据库中导出 CSV、JSON、纯文本或完整的 SQL 转储。
可以这样理解:你告诉命令行工具如何格式化结果(.mode)、是否包含列名(.headers),以及把输出发到哪里(.output)。然后运行一个查询,查询结果就会写进文件。
先建一个小数据库来练习:
三行四列。我们会把它导出成几种格式。
CSV:带表头的 .mode csv
CSV 是最常用的导出格式:电子表格、数据管道和大多数其他工具都支持它。在 sqlite3 命令行中:
sqlite> .mode csv
sqlite> .headers on
sqlite> .output users.csv
sqlite> SELECT * FROM users;
sqlite> .output stdout
刚才发生了什么:
.mode csv把每一行格式化为逗号分隔的值,并给包含逗号、引号或换行符的字段加上引号。.headers on会添加第一行列名。不加的话,CSV 就没有表头,这通常不是你想要的。.output users.csv把结果重定向到文件。从这时起,查询输出会写进文件,而不是显示在屏幕上。SELECT运行后,会悄悄写入文件。.output stdout把输出切换回终端,这样你就能看到下一个查询的结果。
生成的文件:
id,name,email,signup_date
1,"Ada Lovelace",ada@example.com,2025-01-15
2,"Boris Johnson",boris@example.com,2025-02-03
3,"Carmen Diaz",carmen@example.com,2025-03-22
你可以导出任意查询的结果,不只是整张表:先过滤、连接、聚合,再重定向输出:
sqlite> .output recent_users.csv
sqlite> SELECT name, email FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
在系统命令行中一行搞定
你完全不必进入交互式命令行。可以在操作系统的命令行中,把点命令和 SQL 通过管道传给 sqlite3:
sqlite3 mydb.sqlite <<EOF
.headers on
.mode csv
.output users.csv
SELECT * FROM users;
EOF
写脚本和定时任务(cron)时就该用这种形式:可重复执行,无需手动输入。.output 只在本次会话中有效,所以不会把状态泄漏到别处。
JSON:.mode json
如果导出的数据要交给 Web 应用或读取 JSON 的工具,.mode json 会生成一个对象数组,每行一个对象:
sqlite> .mode json
sqlite> .output users.json
sqlite> SELECT * FROM users;
sqlite> .output stdout
文件内容:
[{"id":1,"name":"Ada Lovelace","email":"ada@example.com","signup_date":"2025-01-15"},
{"id":2,"name":"Boris Johnson","email":"boris@example.com","signup_date":"2025-02-03"},
{"id":3,"name":"Carmen Diaz","email":"carmen@example.com","signup_date":"2025-03-22"}]
在 JSON 中,表头隐含在键里,所以 .headers 在这里不起作用。如果你想要自定义结构,比如嵌套对象或重命名字段,就在查询中用 json_object() 构建:
这样每行都会得到一个 JSON 字符串,结构完全由你掌控。再配合 json_group_array(),就能把整个结果汇总成一个 JSON 文档。
完整的 SQL 转储:.dump
.dump 和 CSV、JSON 有本质上的不同。它会生成一个 .sql 文件,以 CREATE TABLE 和 INSERT 语句的形式包含表结构和全部数据,足以从空库重建整个数据库:
sqlite3 mydb.sqlite .dump > backup.sql
输出内容的一个片段:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
signup_date TEXT NOT NULL
);
INSERT INTO users VALUES(1,'Ada Lovelace','ada@example.com','2025-01-15');
INSERT INTO users VALUES(2,'Boris Johnson','boris@example.com','2025-02-03');
INSERT INTO users VALUES(3,'Carmen Diaz','carmen@example.com','2025-03-22');
COMMIT;
恢复则是反向操作:把文件通过管道导入一个新数据库:
sqlite3 restored.sqlite < backup.sql
.dump 适合用来做备份、把测试数据快照纳入版本控制,以及在机器之间迁移数据。它会保留索引、触发器、视图等表结构中的一切。
只转储一张表
.dump 可以接收一个表名(或匹配模式)来限制输出范围:
sqlite3 mydb.sqlite ".dump users" > users_only.sql
这只会转储 users 表的结构和数据行。当你只想把一张表复制到另一个数据库、不想带上其他内容时,这很有用。你也可以用模式匹配:.dump 'log_%' 会转储所有以 log_ 开头的表。
只导出表结构,不要数据
有时你只需要结构而不需要数据行,比如用来写文档、搭建干净的开发环境,或者对比不同数据库的表结构。.schema 只输出 CREATE 语句:
sqlite3 mydb.sqlite .schema > schema.sql
加上表名,就只导出那一张表:
sqlite3 mydb.sqlite ".schema users" > users_schema.sql
输出是纯 SQL,包括 CREATE TABLE、CREATE INDEX、CREATE TRIGGER,可以直接在空数据库上运行。
其他实用模式
除了 CSV 和 JSON,.mode 还有更多选项。下面几个值得了解:
.mode column -- aligned columns, nice for reading at the terminal
.mode markdown -- pipe-separated, GitHub-friendly tables
.mode html -- HTML <table> output
.mode tabs -- tab-separated values (TSV)
.mode insert users -- emits INSERT statements for the named table
.mode quote -- SQL-quoted values, useful for inspection
.mode markdown 非常适合把查询结果粘贴到 README 或合并请求里。.mode insert <table> 是生成种子数据的快捷方式:运行一个 SELECT,拿到 INSERT 语句,粘贴到测试数据文件中。
sqlite> .mode insert users
sqlite> .output seed.sql
sqlite> SELECT * FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
几点实用提示
.output stdout(或不带参数的.output)会恢复终端输出。 忘了这一步,下一个查询的结果就会悄无声息地写进文件。- CSV 导出不保留类型。 文件里的一切都会变成文本,重新导入时需要有目标表结构来解释它。如果需要原样导回另一个 SQLite 数据库,请用
.dump。 - 大量数据的导出是流式进行的。
.output会边生成边写入数据行,所以转储比内存还大的表也没问题。 - 要对正在使用的数据库做热备份,
.dump也可以,但专门的.backup命令(课程后面会讲到)更快也更安全,因为它使用的是 SQLite 的在线备份 API。
下一步:查询数据
现在你已经全面了解了写入数据:INSERT、UPDATE、DELETE、UPSERT、RETURNING、从 CSV 导入,以及把数据导出。接下来是使用数据库的另一半:高效地读取数据。你的大部分时间都会花在 SELECT 语句上,这就是下一页的内容。
常见问题
怎么把 SQLite 表导出为 CSV?
在 sqlite3 命令行中切换到 CSV 模式,打开表头,把输出指向一个文件,然后运行查询:依次执行 .mode csv、.headers on、.output users.csv,再执行 SELECT * FROM users;。完成后运行 .output stdout,让结果重新显示在终端上。
.dump 和导出 CSV 有什么区别?
.dump 会生成一个 .sql 文件,里面有 CREATE TABLE 语句和 INSERT 语句,包含从零重建数据库所需的一切。CSV 只导出一个查询或一张表的行,不包含表结构。备份和迁移用 .dump;把数据交给电子表格或其他工具时用 CSV。
可以把 SQLite 查询结果导出为 JSON 吗?
可以。要么在命令行里设置 .mode json 然后运行任意 SELECT,要么在查询中用内置的 json_object() 和 json_group_array() 函数构建 JSON。临时导出用 .mode json 更简单;用函数则能完全掌控 JSON 的结构。