【问题标题】:How do I dump the data of some SQLite3 tables?如何转储一些 SQLite3 表的数据?
【发布时间】:2010-09-09 16:39:10
【问题描述】:

如何转储数据库的某些 SQLite3 表(不是所有表)的数据,仅转储数据,而不转储模式? 转储应该是 SQL 格式,因为它应该稍后很容易重新输入到数据库中,并且应该从命令行完成。类似的东西

sqlite3 db .dump

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

【问题讨论】:

  • 转成什么格式?特别是什么,或者您只是在寻找人类可读的备份?请说明。
  • 我想转储为 SQL 格式,这样我可以很容易地恢复它。我已将该信息添加到主要问题中。

标签: sql sqlite


【解决方案1】:

您并没有说您希望对转储文件做什么。

获取 CSV 文件(可以导入到几乎所有内容中)

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

获取 SQL 文件(可以重新插入到不同的 SQLite 数据库中)

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

【讨论】:

  • 有没有办法使用 SQL 语句以编程方式执行此操作?我可以看到如何使用解释器来完成,但如果我想写一个脚本呢?
  • 您可以将您的语句放在一个文件中(例如 sample.txt),然后使用以下命令调用它: sqlite3 db.sq3
  • "或者使用 .once 命令而不是 .output 并且输出只会被重定向到单个 next 命令,然后再返回到控制台。使用不带参数的 .output 开始写入标准再次输出。" SQLite docs
【解决方案2】:

您可以这样做以获得 .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;

希望对你有帮助。

【讨论】:

  • @anurageldorado 这是普通的 sql。只需运行sqlite3 some.db &lt; data.sql
  • 对于一些 rasson 不适合我。我需要使用周围。 sqlite3 storage/db/jobs.s3db .schema jobs &gt; schema.sql 不工作,但 echo '.schema' jobs | sqlite3 storage/db/jobs.s3db &gt; schema.sql 工作正常
  • 这似乎是一个很好的解决方案,但在我的情况下,大多数行实际上都被 grep 删除了。 .schema 命令在多行上生成每个表的架构,因此有一行只包含);,而 grep 删除所有包含); 的行,在 grep 中添加-x 选项可以解决此问题。
【解决方案3】:

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

【讨论】:

  • 当我像你提到的那样添加多个表名时,它给了我这个输出:Usage: .dump ?--preserve-rowids? ?LIKE-PATTERN?
  • @mwm 我在sqlite3 3.31.1 (2020/01/27) 中观察到同样的问题。 changelog 对此只字未提。 (顺便说一句,--preserve-rowids 确实有效,但根本没有记录。)
【解决方案4】:

不是最好的方法,但至少不需要外部工具(grep 除外,它是 *nix 盒子的标准)

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

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

请注意,这不包括架构。

【讨论】:

  • 我用过sqlite3 Database.s3db .dump
  • 如果这些插入的值中有换行符,这将中断。按照其他答案之一的建议,更好地使用grep -v '^CREATE'
  • 如果CREATE 语句中有换行符(有时会这样做),则使用grep -v '^CREATE; 将中断。最好的,IMO,根本不会自动删除 CREATE 语句,而是手动编辑它们。只需使用您需要的任何文本编辑器,然后搜索 CREATE 并手动删除这些语句。只要数据库不是很大(而且由于您使用的是 sqlite,我猜它是注释),那么这很简单。
  • 但是创建的 grep 也会从视图中获取创建。我怎样才能删除它?
【解决方案5】:

任何建议使用 grep 排除 CREATE 行或仅从 sqlite3 $DB .dump 输出中获取 INSERT 行的答案都将严重失败。 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

【讨论】:

    【解决方案6】:

    作为对 Paul Egan 答案的改进,可以按如下方式完成:

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

    --或--

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

    当然,需要注意的是您必须安装 grep。

    【讨论】:

    • 我喜欢这个。作为一个额外的好处,如果你有一个转储的 SQL 文件,它仍然可以工作,只是 cat database.sql | grep '^INSERT' &gt; database_inserts.sql(架构相同,替换为 grep '^CREATE'
    • @trisweb,当然你的意思是grep '^INSERT' &lt; database.sql &gt; database_inserts.sql 那个cat 是多余的
    • 没什么多余的。 cat 基本上没有任何执行成本,并且使输入到输出的链更加清晰。当然,你也可以写&lt; database.sql grep '^INSERT' ...,但是显式管道更容易阅读。
    • 当我像你提到的那样添加多个表名时,它给了我这个输出:Usage: .dump ?--preserve-rowids? ?LIKE-PATTERN?
    • -1:使用 CREATE 搜索行是一个无用的想法。几乎每个视图或触发器,尤其是如果它包含 cmets,都需要不止一行。
    【解决方案7】:

    在 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 
    

    【讨论】:

      【解决方案8】:

      审查其他可能的解决方案

      仅包括 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
      

      这是一个不错且可自定义的解决方案,但如果您的列在 spatialite 中具有像“几何”类型这样的 blob 对象,则它不起作用

      用架构区分转储

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

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

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

      这个问题可能没有最佳答案,但对我有用的是 grep 插入,考虑到列值中的新行,expression like this

      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
      

      【讨论】:

        【解决方案9】:

        根据Command Line Shell For SQLite 的 SQLite 文档,您可以将 SQLite 表(或表的一部分)导出为 CSV,只需将“模式”设置为“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”确实存在。

        【讨论】:

          【解决方案10】:

          最好的方法是使用 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)

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

          【讨论】:

            【解决方案11】:

            此版本与插入内的换行符配合得很好:

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

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

            【讨论】:

              【解决方案12】:

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

              最后我写了一个工具来拆分.dump生成的SQL:

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

              【讨论】:

                【解决方案13】:

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

                【讨论】:

                • 我的目的是生成一个可以轻松重新添加到数据库的 SQL 文件。
                猜你喜欢
                • 1970-01-01
                • 2020-03-13
                • 2010-09-23
                • 2015-11-23
                • 1970-01-01
                • 1970-01-01
                • 2010-09-23
                • 1970-01-01
                相关资源
                最近更新 更多