Wie speichere ich die Daten einiger SQLite3-Tabellen?

182

Wie speichere ich die Daten und nur die Daten, nicht das Schema, einiger SQLite3-Tabellen einer Datenbank (nicht aller Tabellen)? Der Speicherauszug sollte im SQL-Format vorliegen, da er später leicht wieder in die Datenbank eingegeben werden kann und über die Befehlszeile erfolgen sollte. Etwas wie

sqlite3 db .dump

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

Pablo
quelle
In welches Format? Etwas Besonderes, oder suchen Sie nur ein lesbares Backup? Bitte angeben.
dmckee --- Ex-Moderator Kätzchen
1
Ich möchte in das SQL-Format kopieren, damit ich es einfach wiederherstellen kann. Ich habe diese Informationen zur Hauptfrage hinzugefügt.
Pupeno

Antworten:

214

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

Ich würde Folgendes verwenden, 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;
CyberFonic
quelle
Gibt es eine Möglichkeit, dies programmgesteuert mithilfe von SQL-Anweisungen durchzuführen? Ich kann mit dem Interpreter sehen, wie es geht, aber was ist, wenn ich ein Skript schreiben wollte?
Coleifer
4
Sie können Ihre Anweisungen in eine Datei (z. B. sample.txt) einfügen und sie dann mit folgendem Befehl aufrufen: sqlite3 db.sq3 <sample.txt
CyberFonic
" Oder verwenden Sie den Befehl .once anstelle von .output, und die Ausgabe wird nur für den einzelnen nächsten Befehl umgeleitet, bevor Sie zur Konsole zurückkehren. Verwenden Sie .output ohne Argumente, um wieder mit dem Schreiben in die Standardausgabe zu beginnen. " SQLite docs
ruffin
156

Sie können dies tun, um einen Unterschied zwischen den Befehlen .schema und .dump zu erhalten. 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 Die Datei enthält nur Daten ohne Schema.

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

Ich hoffe das hilft dir.

Quallen
quelle
5
@anurageldorado es ist einfach SQL. einfach laufensqlite3 some.db < data.sql
Quallen
Für manche Rasson funktioniert das bei mir nicht. Ich brauche Anwendungen um. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlnicht funktionieren, aber gut echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlfunktionieren
abkrim
2
Es schien eine gute Lösung zu sein, aber in meinem Fall werden die meisten Zeilen tatsächlich von grep entfernt. Der Befehl .schema generiert das Schema jeder Tabelle in mehreren Zeilen, sodass nur eine Zeile enthalten ist );, und grep entfernt alle Zeilen, die das );Hinzufügen der -xOption zu grep enthalten, um dieses Problem zu beheben.
Sunder
38

Nicht der beste Weg, benötigt aber zumindest keine externen Tools (außer grep, das auf * nix-Boxen sowieso Standard 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.

mehrsprachig
quelle
1
Ich benutztesqlite3 Database.s3db .dump
Jader Dias
3
Dies wird unterbrochen, wenn diese Einfügungen Zeilenumbrüche in den Werten enthalten. Besser verwenden, grep -v '^CREATE'wie in einer der anderen Antworten vorgeschlagen
Dequis
1
using grep -v '^CREATE;wird unterbrochen, wenn die CREATEAnweisungen Zeilenumbrüche enthalten (was manchmal der Fall ist). Das Beste, IMO, ist, die CREATEAnweisungen nicht automatisch zu entfernen , sondern manuell zu bearbeiten. Verwenden Sie einfach den gewünschten Texteditor und suchen Sie CREATEdiese Anweisungen und entfernen Sie sie manuell. Solange die Datenbank nicht riesig ist (und da Sie SQLite verwenden, würde ich vermuten, dass es ein Hinweis ist), ist dies ziemlich einfach.
Dan Jones
Das Grep des Erstellens übernimmt jedoch auch das Erstellen aus den Ansichten. Wie kann ich das entfernen?
Silve2611
35

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

Paul Egan
quelle
4
Wenn ich wie erwähnt mehrere Tabellennamen hinzufüge, wird folgende Ausgabe angezeigt: Verwendung: .dump? - Erhalten von Rowids? ? LIKE-PATTERN?
MWM
1
@mwm Ich beobachte das gleiche Problem in sqlite3 3.31.1 (2020/01/27). Das Changelog sagt nichts darüber aus. (Funktioniert übrigens, --preserve-rowidsist aber überhaupt nicht dokumentiert.)
21.
11

Jede Antwort, die vorschlägt, grep zu verwenden, um die CREATEZeilen auszuschließen oder nur die INSERTZeilen aus der sqlite3 $DB .dumpAusgabe zu übernehmen, schlägt fehl. In den CREATE TABLEBefehlen wird eine Spalte pro Zeile aufgelistet (sodass beim Ausschließen CREATEnicht alle INSERTSpalten angezeigt werden ), und Werte in den Zeilen können eingebettete Zeilenumbrüche enthalten (sodass Sie nicht nur die INSERTZeilen erfassen können ).

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 filtern $(sqlite $DB .tables | grep -v -e one -e two -e three), oder wenn Sie eine bestimmte Teilmenge erhalten möchten, ersetzen Sie diese durch one two three.

retracile
quelle
9

Als 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.

Drew
quelle
1
Ich mag diesen. Als zusätzlichen Bonus funktioniert es immer noch, wenn eine ausgelagerte SQL-Datei cat database.sql | grep '^INSERT' > database_inserts.sqlgrep '^CREATE'
herumhängt
2
@ Trisweb, natürlich meinst du grep '^INSERT' < database.sql > database_inserts.sqldas catist überflüssig
Sebastian
1
Nichts überflüssiges. Die catAusführung kostet im Grunde nichts und macht die Input-Kette viel klarer. Natürlich können Sie auch schreiben, < database.sql grep '^INSERT' ...aber eine explizite Pipe ist viel einfacher zu lesen.
rjh
1
Wenn ich wie erwähnt mehrere Tabellennamen hinzufüge, wird folgende Ausgabe angezeigt: Verwendung: .dump? - Erhalten von Rowids? ? LIKE-PATTERN?
MWM
-1: Das Suchen nach Zeilen mit CREATE ist eine nutzlose Idee. Fast jede Ansicht oder jeder Auslöser, insbesondere wenn sie Kommentare enthält, erfordert mehr als eine Zeile.
Ceving
6

In Python oder Java oder einer anderen Hochsprache 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 Paneldaten haben, mit anderen Worten, fügen viele einzelne Einträge mit IDs diese dem with look hinzu und es werden auch zusammenfassende Statistiken 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 
Davoud Taghawi-Nejad
quelle
4

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

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

Bitte lesen Sie die weitere Dokumentation zu den beiden zu berücksichtigenden Fällen: (1) Tabelle "tab1" existiert bisher nicht und (2) Tabelle "tab1" existiert bereits.

PeterCo
quelle
3

Die beste Methode wäre, den Code zu verwenden, den der sqlite3-Datenbankspeicherauszug ausführen würde, ausgenommen Schemateile.

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 tatsächlichen Code

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

harningt
quelle
3

Überprüfung anderer möglicher Lösungen

Schließen Sie nur INSERTs ein

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, aber es funktioniert 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 das Grep der Einfügungen unter Berücksichtigung neuer Zeilen in den Spaltenwerten mit einem Ausdruck wie diesem

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

Um die Tabellen auszuwählen, die ausgegeben werden sollen, wird .dumpein LIKE-Argument zugelassen, das mit den Tabellennamen übereinstimmt. Wenn dies jedoch 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

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

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

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

Diese Version funktioniert gut mit Zeilenumbrüchen in Beilagen:

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

In der Praxis werden alle Zeilen ausgeschlossen, mit CREATEdenen weniger wahrscheinlich Zeilenumbrüche enthalten

Elia Schito
quelle
0

Die Antwort von retracile sollte die nächstgelegene sein, funktioniert aber in meinem Fall nicht. Eine Einfügeabfrage ist gerade in der Mitte kaputt gegangen und der Export wurde gerade gestoppt. Ich bin mir nicht sicher, was der Grund ist. Es funktioniert jedoch gut während.dump .

Schließlich schrieb ich ein Tool für die Aufteilung der SQL generiert aus .dump:

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

Walty Yeung
quelle
-3

Sie können in den Tabellen nach jedem Feld Kommas einfügen, um eine CSV zu erstellen, oder ein GUI-Tool verwenden, um alle Daten zurückzugeben und in einer CSV zu speichern.


quelle
2
Meine Absicht war es, eine SQL-Datei zu erstellen, die der Datenbank problemlos wieder hinzugefügt werden kann.
Pupeno