it-swarm-eu.dev

Wie kann ich die Daten einiger SQLite3-Tabellen sichern?

Wie kann ich die Daten und nur die Daten, nicht das Schema, einiger SQLite3-Tabellen einer Datenbank sichern (nicht alle Tabellen)? Der Speicherauszug sollte im SQL-Format vorliegen, da er später problemlos erneut in die Datenbank eingegeben werden kann und über die Befehlszeile erfolgen sollte. So etwas wie

sqlite3 db .dump

aber ohne das Schema zu sichern und auszuwählen, welche Tabellen gesichert werden sollen.

170
pupeno

Sie sagen nicht, was Sie mit der abgelegten Datei tun möchten.

Ich würde folgendes benutzen, um eine CSV-Datei zu erhalten, die ich in fast alles importieren kann

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

Wenn Sie erneut in eine andere SQLite-Datenbank einfügen möchten, gehen Sie wie folgt vor:

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

Sie können dies tun, indem Sie den Unterschied zwischen den Befehlen .schema und .dump ermitteln. Zum Beispiel mit grep:

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

data.sql Datei wird nur Daten ohne Schema enthalten, ungefähr so:

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

Ich hoffe das hilft dir.

144
jellyfish

Nicht der beste Weg, aber benötigt zumindest keine externen Tools (außer grep, das ohnehin Standard bei * nix-Boxen ist)

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

sie müssen diesen Befehl jedoch für jede gesuchte Tabelle ausführen.

Beachten Sie, dass dies kein Schema enthält.

37
polyglot

Sie können ein oder mehrere Tabellenargumente für den Spezialbefehl .dump angeben, z. B. .sqlite3 db ".dump 'table1' 'table2'".

34
Paul Egan

Jede Antwort, die vorschlägt, die Zeilen CREATE mit grep auszuschließen oder nur die Zeilen INSERT aus der Ausgabe sqlite3 $DB .dump Zu holen, schlägt fehl. Mit den Befehlen CREATE TABLE Wird eine Spalte pro Zeile aufgelistet (mit Ausnahme von CREATE wird nicht alles erfasst), und die Werte in den Zeilen INSERT können eingebettete Zeilenumbrüche enthalten (dies ist auch möglich) nicht nur die Zeilen INSERT erfassen).

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

Getestet auf sqlite3 Version 3.6.20.

Wenn Sie bestimmte Tabellen ausschließen möchten, können Sie sie mit $(sqlite $DB .tables | grep -v -e one -e two -e three) filtern, oder wenn Sie eine bestimmte Teilmenge erhalten möchten, ersetzen Sie diese durch one two three.

10
retracile

Als eine Verbesserung der Antwort von Paul Egan kann dies wie folgt erreicht werden:

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

--oder--

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

Die Einschränkung ist natürlich, dass Sie grep installiert haben müssen.

8
Drew

In Python oder Java oder einer höheren Sprache funktioniert der .dump nicht. Wir müssen die Konvertierung in CSV von Hand codieren. Ich gebe ein Python Beispiel. Andere, Beispiele wären willkommen:

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

Wenn Sie Panel-Daten haben, mit anderen Worten, viele einzelne Einträge mit IDs fügen diese zum with look hinzu und es werden auch Übersichtsstatistiken ausgegeben:

        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 

Gemäß der SQLite-Dokumentation für Befehlszeilen-Shell für SQLite können Sie eine SQLite-Tabelle (oder einen Teil einer Tabelle) als CSV exportieren, indem Sie einfach "mode" auf "csv" setzen und dann a ausführen Abfrage, um die gewünschten Zeilen der Tabelle zu extrahieren:

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

Verwenden Sie dann den Befehl ".import", um CSV-Daten (Comma Separated Value) in eine SQLite-Tabelle zu importieren:

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

Lesen Sie bitte die weitere Dokumentation zu den beiden zu berücksichtigenden Fällen: (1) Tabelle "tab1" ist noch nicht vorhanden und (2) Tabelle "tab1" ist bereits vorhanden.

4
PeterCo

Die beste Methode wäre, den Code zu verwenden, den der SQLite3-Datenbankspeicherauszug ausführen würde, mit Ausnahme von Schemateilen.

Beispiel Pseudocode:

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

Sehen: src/Shell.c:838 (für sqlite-3.5.9) für den aktuellen Code

Sie können auch einfach diese Shell nehmen und die Schemateile auskommentieren und diese verwenden.

3
harningt

Überprüfung anderer möglicher Lösungen

Nur INSERTs einschließen

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

Einfach zu implementieren, schlägt jedoch fehl, wenn eine Ihrer Spalten neue Zeilen enthält

SQLite-Einfügemodus

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

Dies ist eine nette und anpassbare Lösung, die jedoch nicht funktioniert, wenn Ihre Spalten Blob-Objekte wie den Typ "Geometrie" in "Spatialite" enthalten

Diff den Dump mit dem Schema

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

Ich weiß nicht warum, arbeite aber nicht für mich

Eine andere (neue) mögliche Lösung

Wahrscheinlich gibt es keine beste Antwort auf diese Frage, aber eine, die für mich funktioniert, ist, die Einfügungen unter Berücksichtigung der neuen Zeilen in den Spaltenwerten mit einem Ausdruck wie dieser zu prüfen

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

Wählen Sie die Tabellen aus, die ausgegeben werden sollen .dump lässt ein LIKE-Argument zu, das mit den Tabellennamen übereinstimmt, aber wenn dies nicht ausreicht, ist wahrscheinlich ein einfaches Skript die bessere Option

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

oder etwas Ausgefeilteres, um Fremdschlüssel zu respektieren und den gesamten Speicherauszug in nur einer Transaktion zu kapseln

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

Beachten Sie, dass der grep-Ausdruck fehlschlägt, wenn ); ist eine Zeichenfolge, die in einer der Spalten vorhanden ist

So stellen Sie es wieder her (in einer Datenbank mit den bereits erstellten Tabellen)

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

Diese Version funktioniert gut mit Zeilenumbrüchen in Beilagen:

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

In der Praxis werden alle Zeilen ausgeschlossen, die mit CREATE beginnen, was weniger wahrscheinlich ist, dass sie neue Zeilen enthalten

2
Elia Schito

Die Antwort von retracile sollte die naheliegendste sein, funktioniert aber in meinem Fall nicht. Eine Insert-Abfrage brach gerade in der Mitte ab und der Export wurde gerade gestoppt. Nicht sicher, was der Grund ist. Es funktioniert jedoch gut während .dump.

Zum Schluss habe ich ein Tool für die Aufteilung der aus .dump Generierten SQL geschrieben:

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

0
Walty Yeung