it-swarm-pt.tech

Como despejo os dados de algumas tabelas SQLite3?

Como eu despejo os dados e apenas os dados, não o esquema, de algumas tabelas SQLite3 de um banco de dados (não todas as tabelas)? O dump deve estar no formato SQL, já que ele deve ser reinserido no banco de dados mais tarde e deve ser feito a partir da linha de comando. Algo como

sqlite3 db .dump

mas sem despejar o esquema e selecionar quais tabelas despejar.

168
pupeno

Você não diz o que deseja fazer com o arquivo descartado.

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

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

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

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

Você pode fazer isso obtendo diferença de 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 arquivo conterá apenas dados sem esquema, algo assim:

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

Espero que isso ajude você.

143
jellyfish

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

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

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

Observe que isso não inclui o esquema.

37
polyglot

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

34
Paul Egan

Qualquer resposta que sugira usar o grep para excluir as linhas CREATE ou simplesmente pegar as linhas INSERT da saída sqlite3 $DB .dump falhará mal. Os comandos CREATE TABLE listam uma coluna por linha (portanto, excluindo CREATE não obterá tudo isso), e os valores nas linhas INSERT podem ter novas linhas incorporadas (portanto, você não pode pegar apenas as linhas INSERT).

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ê quiser excluir certas tabelas, você pode filtrá-las com $(sqlite $DB .tables | grep -v -e one -e two -e three) ou, se quiser obter um subconjunto específico, substituí-las por one two three.

10
retracile

Como uma melhoria para a resposta de Paul Egan, isso pode ser feito da seguinte forma:

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.

8
Drew

Em Python ou Java ou em qualquer linguagem de alto nível, o .dump não funciona. Precisamos codificar a conversão para CSV manualmente. Eu dou um exemplo 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 de painel, em outras palavras, muitas entradas individuais com id's adicionam isso ao look e também despeja 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 
6
Davoud Taghawi-Nejad

De acordo com a documentação do SQLite para Shell de linha de comando para SQLite você pode exportar uma tabela SQLite (ou parte de uma tabela) como CSV, simplesmente definindo o "modo" para "csv" e então executar um consulta para extrair as linhas desejadas da tabela:

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 (valores separados por vírgulas) em uma tabela SQLite:

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

Por favor, 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.

4
PeterCo

O melhor método seria pegar o código que o db sqlite3 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

Veja: src/Shell.c:838 (para sqlite-3.5.9) para código real

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

3
harningt

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

Incluir apenas INSERTs

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

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

Modo de inserção de 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 "Geometry" na espacialidade

Diff 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 tenho certeza porque, mas não está funcionando para mim

Outra (nova) solução possível

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

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

Para selecionar as tabelas que serão descartadas, .dump admite um argumento LIKE para coincidir com os nomes das tabelas, mas se isso não for suficiente, provavelmente um script simples é uma opção melhor

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

Tenha em conta que a expressão grep falhará se ); for 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
3
Francisco Puga

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 que começam com CREATE, que é menos provável de conter novas linhas

2
Elia Schito

A resposta de retracile deve ser a mais próxima, mas não funciona para o meu caso. Uma consulta de inserção acabou de ser quebrada no meio e a exportação foi interrompida. Não tenho certeza qual é o motivo. No entanto, funciona bem durante .dump.

Finalmente eu escrevi uma ferramenta para dividir o SQL gerado a partir de .dump:

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

0
Walty Yeung