关于sql:如何转储某些SQLite3表的数据?

关于sql:如何转储某些SQLite3表的数据?

How do I dump the data of some SQLite3 tables?

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

1
sqlite3 db .dump

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


您没有说要对转储的文件做什么。

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

1
2
3
4
5
.mode csv
-- use '.separator SOME_STRING' for something other than a comma.
.headers ON
.out file.csv
SELECT * FROM MyTable;

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

1
2
3
.mode INSERT <target_table_name>
.out file.sql
SELECT * FROM MyTable;

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

1
2
3
sqlite3 SOME.db .schema > schema.sql
sqlite3 SOME.db .dump > dump.sql
grep -vx -f schema.sql dump.sql > DATA.sql

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

1
2
3
4
5
6
BEGIN TRANSACTION;
INSERT INTO"table1" VALUES ...;
...
INSERT INTO"table2" VALUES ...;
...
COMMIT;

我希望这可以帮助你。


这不是最好的方法,但至少不需要外部工具(grep除外,它始终是* nix盒上的标准配置)

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

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

请注意,这不包括架构。


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


任何建议使用grep排除CREATE行或仅从sqlite3 $DB .dump输出中抓住INSERT行的答案都将严重失败。 CREATE TABLE命令每行列出一列(因此排除CREATE不会得到全部),并且INSERT行上的值可以嵌入换行符(因此您不能仅抓取INSERT行)。

1
2
3
4
FOR t IN $(sqlite3 $DB .tables); do
    echo -e".mode insert $t
select * 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替换它们。


作为对保罗·伊根(Paul Egan)答案的改进,可以按以下步骤完成:

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

- 要么 -

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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外观中,并且还会转储摘要统计信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
        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

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

1
2
3
4
5
sqlite> .header ON
sqlite> .mode csv
sqlite> .once c:/WORK/dataout.csv
sqlite> SELECT * FROM tab1;
sqlite> .exit

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

1
2
3
sqlite> .mode csv
sqlite> .import C:/WORK/dataout.csv tab1
sqlite> .exit

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


审查其他可能的解决方案

仅包括INSERT

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

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

SQLite插入模式

1
2
3
4
FOR t IN $(sqlite3 $DB .tables); do
    echo -e".mode insert $t
select * from $t;"

done | sqlite3 $DB > backup.sql

这是一个不错的且可自定义的解决方案,但如果您的列在spacespaceite中具有Blob对象(例如" Geometry"类型),则该方法将无效

与模式差异转储

1
2
3
sqlite3 SOME.db .schema > schema.sql
sqlite3 SOME.db .dump > dump.sql
grep -v -f schema.sql dump > DATA.sql

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

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

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

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

要选择要转储的表,.dump允许使用LIKE参数来匹配表名,但是如果这样做还不够,则可能使用简单的脚本是更好的选择

1
2
3
4
5
6
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

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

1
2
3
4
5
6
7
8
9
10
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表达式将失败

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

1
sqlite3 -bail DATABASE.db3 < /tmp/backup.sql

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

伪代码示例:

1
2
3
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并注释掉架构部分并使用它。


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

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

实际上,排除以CREATE开头的所有行(不太可能包含换行符)


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

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

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


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


推荐阅读