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.
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;
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.
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.
Puoi specificare uno o più argomenti di tabella con il comando speciale .dump, ad es .sqlite3 db ".dump 'table1' 'table2'"
.
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
.
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.
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
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à.
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.
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
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
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
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
: