it-swarm.it

Come posso scaricare i dati di alcune tabelle SQLite3?

Come posso scaricare i dati e solo i dati, non lo schema, di alcune tabelle SQLite3 di un database (non tutte le tabelle)? Il dump dovrebbe essere in formato SQL, poiché dovrebbe essere facilmente reinserito nel database in un secondo momento e dovrebbe essere eseguito dalla riga di comando. Qualcosa di simile a

sqlite3 db .dump

ma senza scaricare lo schema e selezionando quali tabelle scaricare.

170
pupeno

Non dici cosa vuoi fare con il file scaricato.

Vorrei usare quanto segue per ottenere un file CSV, che posso importare in quasi tutto

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

Se si desidera reinserire in un database SQLite diverso, quindi:

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

Puoi farlo ottenendo la differenza tra i comandi .schema e .dump. ad esempio con grep:

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

Il file data.sql Conterrà solo i dati senza schema, qualcosa del genere:

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

Spero che questo ti aiuta.

144
jellyfish

Non è il modo migliore, ma al leasing non ha bisogno di strumenti esterni (tranne grep, che è comunque standard su * nix box)

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

ma devi eseguire questo comando per ogni tabella che stai cercando.

Si noti che questo non include lo schema.

37
polyglot

Puoi specificare uno o più argomenti di tabella con il comando speciale .dump, ad es .sqlite3 db ".dump 'table1' 'table2'".

34
Paul Egan

Qualsiasi risposta che suggerisce di usare grep per escludere le righe CREATE o semplicemente afferrare le righe INSERT dall'output sqlite3 $DB .dump Fallirà male. I comandi CREATE TABLE Elencano una colonna per riga (quindi escludendo CREATE non la otterrà tutta), e i valori sulle righe INSERT possono avere righe incorporate (così puoi prendi solo le righe INSERT).

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

Testato su sqlite3 versione 3.6.20.

Se si desidera escludere determinate tabelle, è possibile filtrarle con $(sqlite $DB .tables | grep -v -e one -e two -e three) o se si desidera ottenere un sottoinsieme specifico sostituirlo con one two three.

10
retracile

Come miglioramento della risposta di Paul Egan, questo può essere realizzato come segue:

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

--o--

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

L'avvertimento, ovviamente, è che devi avere grep installato.

8
Drew

In Python o Java o in qualsiasi linguaggio di alto livello il .dump non funziona. Dobbiamo codificare manualmente la conversione in CSV. Do un esempio Python. Altri, sarebbero apprezzati esempi:

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 disponi di "dati pannello", in altre parole molte singole voci con ID aggiungono questo aspetto e scarica anche le statistiche di riepilogo:

        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

Secondo la documentazione di SQLite per Command Line Shell For SQLite è possibile esportare una tabella SQLite (o parte di una tabella) come CSV, semplicemente impostando la "modalità" su "csv" e quindi eseguire un query per estrarre le righe desiderate della tabella:

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

Quindi utilizzare il comando ".import" per importare i dati CSV (valori separati da virgola) in una tabella SQLite:

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

Leggere la documentazione aggiuntiva sui due casi da considerare: (1) La tabella "tab1" non esiste in precedenza e (2) la tabella "tab1" esiste già.

4
PeterCo

Il metodo migliore sarebbe quello di prendere il codice che farebbe il dump sqlite3 db, escludendo le parti dello schema.

Esempio di pseudo codice:

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

Vedi: src/Shell.c:838 (per sqlite-3.5.9) per il codice effettivo

Potresti anche semplicemente prendere quella Shell e commentare le parti dello schema e usarlo.

3
harningt

Revisione di altre possibili soluzioni

Includi solo INSERTI

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

Facile da implementare ma fallirà se una delle tue colonne include nuove linee

Modalità inserimento SQLite

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

Questa è una soluzione piacevole e personalizzabile, ma non funziona se le colonne hanno oggetti BLOB come il tipo "Geometria" in spatialite

Diff il dump con lo schema

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

Non so perché, ma non funziona per me

Un'altra (nuova) soluzione possibile

Probabilmente non c'è una risposta migliore a questa domanda, ma una cosa che funziona per me è grep gli inserti tenendo conto che ci sono nuove righe nei valori della colonna con un espressione come questa

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

Per selezionare le tabelle, eseguire il dump .dump ammette un argomento LIKE per abbinare i nomi delle tabelle, ma se questo non è abbastanza probabilmente un semplice script è l'opzione migliore

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

o, qualcosa di più elaborato per rispettare le chiavi esterne e incapsulare tutto il dump in una sola transazione

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

Tieni presente che l'espressione grep fallirà se ); è una stringa presente in una delle colonne

Per ripristinarlo (in un database con le tabelle già create)

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

Questa versione funziona bene con le nuove linee all'interno degli inserti:

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

In pratica esclude tutte le righe che iniziano con CREATE che ha meno probabilità di contenere newline

2
Elia Schito

La risposta di retracile dovrebbe essere la più vicina, ma non funziona nel mio caso. Una query di inserimento si è appena interrotta nel mezzo e l'esportazione si è appena fermata. Non sono sicuro di quale sia la ragione. Tuttavia funziona benissimo durante .dump.

Alla fine ho scritto uno strumento per suddividere l'SQL generato da .dump:

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

0
Walty Yeung