Como despejo os dados de algumas tabelas SQLite3?

183

Como despejo os dados, e somente os dados, e não o esquema, de algumas tabelas SQLite3 de um banco de dados (nem todas as tabelas)? O dump deve estar no formato SQL, pois deve ser facilmente inserido novamente no banco de dados posteriormente e deve ser feito na linha de comando. Algo como

sqlite3 db .dump

mas sem despejar o esquema e selecionar quais tabelas despejar.

Pablo
fonte
Para qual formato? Alguma coisa em particular, ou você está apenas procurando um backup legível por humanos? Por favor especifique.
dmckee --- gatinho ex-moderador
1
Quero despejar no formato SQL, para poder restaurá-lo facilmente. Eu adicionei essa informação à pergunta principal.
pupeno 18/09/08

Respostas:

214

Você não está dizendo o que deseja fazer com o arquivo despejado.

Eu usaria o seguinte para obter um arquivo CSV, que eu possa importar em quase tudo

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

Se você deseja reinserir em um banco de dados SQLite diferente, então:

.mode insert <target_table_name>
.out file.sql 
select * from MyTable;
CyberFonic
fonte
Existe uma maneira de fazer isso programaticamente usando instruções SQL? Posso ver como fazer isso usando o intérprete, mas e se eu quisesse escrever um script?
coleifer
4
Você pode colocar suas instruções em um arquivo (por exemplo, sample.txt) e depois invocá-lo usando: sqlite3 db.sq3 <sample.txt
CyberFonic
" Ou use o comando .once em vez de .output e output será redirecionado apenas para o próximo comando antes de reverter para o console. Use .output sem argumentos para começar a gravar novamente na saída padrão. " SQLite docs
ruffin
156

Você pode fazer isso obtendo a diferença dos comandos .schema e .dump. por exemplo com grep:

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

data.sql O arquivo conterá apenas dados sem esquema, algo como isto:

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

Espero que isso ajude você.

água-viva
fonte
5
@anurageldorado é sql simples. apenas execute #sqlite3 some.db < data.sql
jellyfish
Para alguns rasson não funciona para mim. Eu preciso de usos por aí. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlnão funciona, mas echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlfunciona bem
abkrim
2
Parecia uma boa solução, mas no meu caso a maioria das linhas está sendo removida pelo grep. O comando .schema gera o esquema de cada tabela em várias linhas, portanto, há uma linha contendo apenas );, e o grep remove todas as linhas que contêm );Adicionar a -xopção ao grep resolve esse problema.
Sunder
38

Não é a melhor maneira, mas, pelo menos, não precisa de ferramentas externas (exceto grep, que é padrão nas caixas * nix de qualquer maneira)

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

mas você precisa executar este comando para cada tabela que está procurando.

Observe que isso não inclui o esquema.

poliglota
fonte
1
Eu useisqlite3 Database.s3db .dump
Jader Dias
3
Isso será interrompido se essas inserções tiverem novas linhas nos valores. Melhor usar grep -v '^CREATE'como sugerido em uma das outras respostas
dequis 22/09/14
1
using grep -v '^CREATE;será interrompido se as CREATEinstruções tiverem quebras de linha (o que às vezes ocorrem). O melhor, IMO, é não retirar automaticamente as CREATEinstruções, mas editá-las manualmente. Basta usar o editor de texto que você precisa e procurar CREATEe remover manualmente essas instruções. Contanto que o banco de dados não seja enorme (e como você está usando o sqlite, acho que é nota), isso é bem simples.
Dan Jones
mas o grep da criação também utilizará a criação nas visualizações. como posso remover isso?
precisa saber é o seguinte
35

Você pode especificar um ou mais argumentos da tabela para o comando especial .dump, por exemplo sqlite3 db ".dump 'table1' 'table2'".

Paul Egan
fonte
4
quando adiciono vários nomes de tabela, como você mencionou, ele me fornece esta saída: Uso: .dump? - preserve-rowids? Como padrão?
Mwm
1
@mwm Estou observando o mesmo problema em sqlite3 3.31.1 (2020/01/27). O changelog não diz nada sobre isso. (A propósito, --preserve-rowidsfunciona, mas não está documentado.)
ynn
11

Qualquer resposta que sugira o uso de grep para excluir as CREATElinhas ou apenas pegar as INSERTlinhas da sqlite3 $DB .dumpsaída falhará muito. Os CREATE TABLEcomandos listam uma coluna por linha (portanto, a exclusão CREATEnão será tudo) e os valores nas INSERTlinhas podem incluir novas linhas incorporadas (para que você não possa pegar apenas as INSERTlinhas).

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

Testado no sqlite3 versão 3.6.20.

Se você deseja excluir determinadas tabelas, pode filtrá-las $(sqlite $DB .tables | grep -v -e one -e two -e three)ou, se deseja obter um subconjunto específico, substitua-o por one two three.

retrátil
fonte
9

Como uma melhoria na resposta de Paul Egan, isso pode ser realizado da seguinte maneira:

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

--ou--

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

A ressalva, é claro, é que você precisa ter o grep instalado.

Desenhou
fonte
1
Eu gosto deste. Como um bônus adicional, ele ainda funciona se você tiver um despejado arquivo SQL pendurado ao redor, apenas cat database.sql | grep '^INSERT' > database_inserts.sql(o mesmo para esquema, substitua-o porgrep '^CREATE'
trisweb
2
@trisweb, é claro que você quer dizer grep '^INSERT' < database.sql > database_inserts.sqlque caté supérfluo
Sebastian
1
Nada de supérfluo. Os catcustos basicamente nada para executar e tornam a cadeia de entrada e saída muito mais clara. Obviamente, você também pode escrever, < database.sql grep '^INSERT' ...mas um canal explícito é muito mais fácil de ler.
rjh
1
quando adiciono vários nomes de tabela, como você mencionou, ele me fornece esta saída: Uso: .dump? - preserve-rowids? Como padrão?
Mwm
-1: pesquisar linhas com CREATE é uma ideia inútil. Quase todas as visualizações ou gatilhos, especialmente se contiverem comentários, requerem mais de uma linha.
ceving 11/12/19
6

Em Python ou Java ou qualquer linguagem de alto nível, o .dump não funciona. Precisamos codificar a conversão para CSV manualmente. Eu dou um exemplo de Python. Outros, exemplos seriam apreciados:

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

Se você tiver 'dados do painel, em outras palavras, muitas entradas individuais com IDs adicionam isso ao com look e também despejam estatísticas de resumo:

        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 
Davoud Taghawi-Nejad
fonte
4

De acordo com a documentação SQLite do Command Line Shell For SQLite, você pode exportar uma tabela SQLite (ou parte de uma tabela) como CSV, simplesmente configurando o "mode" como "csv" e, em seguida, execute uma consulta para extrair as linhas desejadas. a mesa:

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

Em seguida, use o comando ".import" para importar dados CSV (valor separado por vírgula) em uma tabela SQLite:

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

Leia a documentação adicional sobre os dois casos a serem considerados: (1) a tabela "tab1" não existe anteriormente e (2) a tabela "tab1" já existe.

PeterCo
fonte
3

O melhor método seria usar o código que o dump sqlite3 db faria, excluindo as partes do esquema.

Exemplo de pseudocódigo:

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

Consulte: src/shell.c:838 (para sqlite-3.5.9) para obter o código real

Você pode até pegar esse shell e comentar as partes do esquema e usá-lo.

harningt
fonte
3

Revisão de outras soluções possíveis

Incluir apenas INSERTs

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

Fácil de implementar, mas falhará se alguma de suas colunas incluir novas linhas

Modo de inserção SQLite

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

Essa é uma solução agradável e personalizável, mas não funciona se suas colunas tiverem objetos de blob como o tipo 'Geometria' em espacialidade

Difere o despejo com o esquema

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

Não sei por que, mas não está funcionando para mim

Outra (nova) solução possível

Provavelmente não há uma resposta melhor para essa pergunta, mas uma que está funcionando para mim é grep as inserções, levando em consideração que há novas linhas nos valores da coluna com uma expressão como esta

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

Para selecionar as tabelas a serem despejadas, .dumpadmite um argumento LIKE para corresponder aos nomes das tabelas, mas se isso não for suficiente, provavelmente um script simples é a melhor opção

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

ou, algo mais elaborado para respeitar chaves estrangeiras e encapsular todo o despejo em apenas uma transação

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

Leve em consideração que a expressão grep falhará se );houver uma string presente em qualquer uma das colunas

Para restaurá-lo (em um banco de dados com as tabelas já criadas)

sqlite3 -bail database.db3 < /tmp/backup.sql
Francisco Puga
fonte
2

Esta versão funciona bem com novas linhas dentro de inserções:

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

Na prática, exclui todas as linhas iniciadas pelas CREATEquais é menos provável que contenham novas linhas

Elia Schito
fonte
0

A resposta por retracile deve ser a mais próxima, mas não funciona no meu caso. Uma consulta de inserção apenas quebrou no meio e a exportação simplesmente parou. Não tenho certeza qual é o motivo. No entanto, funciona bem durante .dump.

Por fim, escrevi uma ferramenta para dividir o SQL gerado a partir de .dump:

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

Walty Yeung
fonte
-3

Você pode fazer uma seleção nas tabelas inserindo vírgulas após cada campo para produzir um csv ou usar uma ferramenta GUI para retornar todos os dados e salvá-los em um csv.


fonte
2
Minha intenção era produzir um arquivo SQL que pudesse ser facilmente adicionado novamente ao banco de dados.
Pupeno 20/10/08