如何转储某些SQLite3表的数据?


182

我该如何转储数据库的某些SQLite3表(而非所有表)的数据,而仅转储数据,而不是模式?转储应采用SQL格式,因为以后应轻松将其重新输入数据库并应从命令行完成。就像是

sqlite3 db .dump

但不转储架构并选择要转储的表。


以什么格式?尤其是什么,或者您只是在寻找人类可读的备份?请明确说明。
dmckee ---前主持人小猫

1
我想转储为SQL格式,以便可以轻松还原它。我已将该信息添加到主要问题中。
pupeno

Answers:


214

您并不是说要对转储的文件做什么。

我将使用以下内容获取CSV文件,该文件可以导入几乎所有内容

.mode csv 
-- use '.separator SOME_STRING' for something other than a comma.
.headers on 
.out file.csv 
select * from MyTable;

如果您想重新插入另一个SQLite数据库,则:

.mode insert <target_table_name>
.out file.sql 
select * from MyTable;

有没有办法使用SQL语句以编程方式执行此操作?我可以看到使用解释器的方法,但是如果我想编写脚本怎么办?
coleifer14年

4
您可以将语句放入文件(例如sample.txt)中,然后使用以下命令调用它:sqlite3 db.sq3 <sample.txt
Cyber​​Fonic 2014年

或者使用.once命令而不是.output,并且仅将下一个命令重定向到输出,然后再返回到控制台。使用不带任何参数的.output重新开始写入标准输出。SQLite文档
Ruffin

156

您可以这样做来获得.schema和.dump命令的区别。例如使用grep:

sqlite3 some.db .schema > schema.sql
sqlite3 some.db .dump > dump.sql
grep -vx -f schema.sql dump.sql > data.sql

data.sql 文件将仅包含没有模式的数据,如下所示:

BEGIN TRANSACTION;
INSERT INTO "table1" VALUES ...;
...
INSERT INTO "table2" VALUES ...;
...
COMMIT;

我希望这可以帮助你。


5
@anurageldorado这是纯SQL。刚运行sqlite3 some.db < data.sql
水母

对于一些拉森不适合我。我需要周围的用途。sqlite3 storage/db/jobs.s3db .schema jobs > schema.sql不起作用,但echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sql可以正常工作
abkrim

2
看来这是一个不错的解决方案,但就我而言,大多数行实际上已被grep删除。.schema命令在多行上生成每个表的架构,因此有一行仅包含);,并且grep删除了所有包含的行。向grep );添加-x选项可解决此问题。
桑德(Sunder)2013年

38

这不是最好的方法,但是至少不需要外部工具(grep除外,反正这在* nix盒上是标准的)

sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"'

但是您确实需要对要查找的每个表执行此命令。

请注意,这不包括架构。


1
我曾经用过sqlite3 Database.s3db .dump
Jader Dias

3
如果这些插入的值中包含换行符,则此操作将中断。grep -v '^CREATE'根据其他答案之一的建议更好地使用
要求

1
grep -v '^CREATE;如果CREATE语句中有换行符(有时会这样做),则使用将中断。IMO最好的办法是根本不自动删除这些CREATE语句,而是手动对其进行编辑。只需使用所需的任何文本编辑器,然后搜索CREATE并手动删除这些语句即可。只要数据库不是很大(并且由于您使用的是sqlite,我想应该注意),那么这很简单。
丹·琼斯

但是创建的grep也会从视图中获取创建的内容。我该如何删除?
Silve2611 '16

35

您可以为.dump特殊命令指定一个或多个表参数,例如sqlite3 db ".dump 'table1' 'table2'"


4
当我按照您提到的方式添加多个表名时,它给出以下输出:用法:.dump?-preserve-rowids??喜欢吗?
mwm

1
@mwm我在观察到相同的问题sqlite3 3.31.1 (2020/01/27)。该更新日志说什么有关。(顺便说一句,--preserve-rowids可以工作,但完全没有记录。)
ynn

11

任何建议使用grep排除CREATE行或仅从输出中获取INSERT行的答案都sqlite3 $DB .dump将严重失败。这些CREATE TABLE命令在每行中列出一列(因此不包括CREATE所有内容),并且这些INSERT行中的值可以嵌入换行符(因此您不能仅抓取这些INSERT行)。

for t in $(sqlite3 $DB .tables); do
    echo -e ".mode insert $t\nselect * from $t;"
done | sqlite3 $DB > backup.sql

在sqlite3 3.6.20版上测试。

如果要排除某些表,可以使用进行过滤$(sqlite $DB .tables | grep -v -e one -e two -e three),或者如果要获取特定的子集,则用替换one two three


9

作为对保罗·伊根(Paul Egan)答案的改进,可以通过以下方式实现:

sqlite3 database.db3 '.dump "table1" "table2"' | grep '^INSERT'

- 要么 -

sqlite3 database.db3 '.dump "table1" "table2"' | grep -v '^CREATE'

注意,当然,您必须安装grep。


1
我喜欢这一个。另外,如果有一个转储的SQL文件cat database.sql | grep '^INSERT' > database_inserts.sqlgrep '^CREATE'
挂在上面

2
@trisweb,当然,你的意思是grep '^INSERT' < database.sql > database_inserts.sqlcat是多余的
塞巴斯蒂安

1
没什么多余的。在cat基本上不费分文执行,使投入产出链更加清晰。当然,您也可以编写,< database.sql grep '^INSERT' ...但是显式管道更易于阅读。
rjh

1
当我按照您提到的方式添加多个表名时,它给出以下输出:用法:.dump?-preserve-rowids??喜欢吗?
mwm

-1:使用CREATE搜索行是没有用的主意。特别是几乎每个视图或触发器(如果包含注释)都需要多于一行。
ceving

6

在Python或Java或任何高级语言中,.dump不起作用。我们需要手动将转换编码为CSV。我举一个Python示例。其他的,例子将不胜感激:

from os import path   
import csv 

def convert_to_csv(directory, db_name):
    conn = sqlite3.connect(path.join(directory, db_name + '.db'))
    cursor = conn.cursor()
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    tables = cursor.fetchall()
    for table in tables:
        table = table[0]
        cursor.execute('SELECT * FROM ' + table)
        column_names = [column_name[0] for column_name in cursor.description]
        with open(path.join(directory, table + '.csv'), 'w') as csv_file:
            csv_writer = csv.writer(csv_file)
            csv_writer.writerow(column_names)
            while True:
                try:
                    csv_writer.writerow(cursor.fetchone())
                except csv.Error:
                    break

如果您具有“面板数据”,换句话说,许多具有id的单独条目会将其添加到with外观中,并且还会转储摘要统计信息:

        if 'id' in column_names:
            with open(path.join(directory, table + '_aggregate.csv'), 'w') as csv_file:
                csv_writer = csv.writer(csv_file)
                column_names.remove('id')
                column_names.remove('round')
                sum_string = ','.join('sum(%s)' % item for item in column_names)
                cursor.execute('SELECT round, ' + sum_string +' FROM ' + table + ' GROUP BY round;')
                csv_writer.writerow(['round'] + column_names)
                while True:
                    try:
                        csv_writer.writerow(cursor.fetchone())
                    except csv.Error:
                        break 

4

根据命令行外壳程序的SQLite文档对于SQLite,只需将“模式”设置为“ csv”,然后运行查询以提取所需的行,即可将SQLite表(或表的一部分)导出为CSV。桌子:

sqlite> .header on
sqlite> .mode csv
sqlite> .once c:/work/dataout.csv
sqlite> SELECT * FROM tab1;
sqlite> .exit

然后使用“ .import”命令将CSV(逗号分隔值)数据导入到SQLite表中:

sqlite> .mode csv
sqlite> .import C:/work/dataout.csv tab1
sqlite> .exit

请阅读有关这两种情况的更多文档:(1)表“ tab1”以前不存在,并且(2)表“ tab1”已存在。


3

最好的方法是采用sqlite3 db dump可以执行的代码,但不包括模式部分。

伪代码示例:

SELECT 'INSERT INTO ' || tableName || ' VALUES( ' || 
  {for each value} ' quote(' || value || ')'     (+ commas until final)
|| ')' FROM 'tableName' ORDER BY rowid DESC

有关src/shell.c:838 实际代码,请参见:(对于sqlite-3.5.9)

您甚至可以只使用该shell并注释掉架构部分并使用它。


3

审查其他可能的解决方案

仅包括INSERT

sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"'

易于实现,但是如果您的任何列中包含新行,它将失败

SQLite插入模式

for t in $(sqlite3 $DB .tables); do
    echo -e ".mode insert $t\nselect * from $t;"
done | sqlite3 $DB > backup.sql

这是一个不错的且可自定义的解决方案,但如果您的列在spacespaceite中具有blob对象(例如“ Geometry”类型),则该方法不起作用

与模式差异转储

sqlite3 some.db .schema > schema.sql
sqlite3 some.db .dump > dump.sql
grep -v -f schema.sql dump > data.sql

不知道为什么,但对我不起作用

另一个(新的)可能的解决方案

这个问题可能没有最佳答案,但是对我有用的一个问题是grep插入内容,考虑到列值中的换行符是这样的:

grep -Pzo "(?s)^INSERT.*\);[ \t]*$"

要选择要转储的表,请.dump输入LIKE参数以匹配表名,但是如果这样做还不够,那么可能最好使用简单的脚本

TABLES='table1 table2 table3'

echo '' > /tmp/backup.sql
for t in $TABLES ; do
    echo -e ".dump ${t}" | sqlite3 database.db3 | grep -Pzo "(?s)^INSERT.*?\);$" >> /tmp/backup.sql
done

或者,更详细地说明如何尊重外键并将所有转储封装在一个事务中

TABLES='table1 table2 table3'

echo 'BEGIN TRANSACTION;' > /tmp/backup.sql
echo '' >> /tmp/backup.sql
for t in $TABLES ; do
    echo -e ".dump ${t}" | sqlite3 $1 | grep -Pzo "(?s)^INSERT.*?\);$" | grep -v -e 'PRAGMA foreign_keys=OFF;' -e 'BEGIN TRANSACTION;' -e 'COMMIT;' >> /tmp/backup.sql
done

echo '' >> /tmp/backup.sql
echo 'COMMIT;' >> /tmp/backup.sql

考虑到如果);任何列中都存在字符串,则grep表达式将失败

还原它(在已创建表的数据库中)

sqlite3 -bail database.db3 < /tmp/backup.sql

2

此版本可与插入符内的换行符一起使用:

sqlite3 database.sqlite3 .dump | grep -v '^CREATE'

实际上,排除所有CREATE以换行开头的行都不太可能


0

retracile的答案应该是最接近的答案,但它不适用于我的情况。一个插入查询刚刚在中间中断,并且导出刚刚停止。不知道是什么原因。但是,它在期间工作正常.dump

最后,我编写了一个工具,用于拆分从生成的SQL .dump

https://github.com/motherapp/sqlite_sql_parser/


-3

您可以在表格上进行选择,在每个字段后插入逗号以产生csv,或使用GUI工具返回所有数据并将其保存到csv。


2
我的意图是产生一个可以轻松地重新添加到数据库的SQL文件。
2008年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.