Konvertieren Sie die SQLITE SQL-Dump-Datei in POSTGRESQL

96

Ich habe die Entwicklung mit einer SQLITE-Datenbank mit Produktion in POSTGRESQL durchgeführt. Ich habe gerade meine lokale Datenbank mit einer großen Datenmenge aktualisiert und muss eine bestimmte Tabelle in die Produktionsdatenbank übertragen.

Basierend auf der Ausführung sqlite database .dump > /the/path/to/sqlite-dumpfile.sqlgibt SQLITE einen Tabellendump im folgenden Format aus:

BEGIN TRANSACTION;
CREATE TABLE "courses_school" ("id" integer PRIMARY KEY, "department_count" integer NOT NULL DEFAULT 0, "the_id" integer UNIQUE, "school_name" varchar(150), "slug" varchar(50));
INSERT INTO "courses_school" VALUES(1,168,213,'TEST Name A',NULL);
INSERT INTO "courses_school" VALUES(2,0,656,'TEST Name B',NULL);
....
COMMIT;

Wie konvertiere ich das oben Genannte in eine POSTGRESQL-kompatible Dump-Datei, die ich in meinen Produktionsserver importieren kann?

DevX
quelle
1
Nun, dieser Befehl funktionierte nicht für mich, bis ich sqlite in sqlite3
Celal Ergün

Antworten:

100

Sie sollten in der Lage sein, diese Dump-Datei direkt in Folgendes einzugeben psql:

/path/to/psql -d database -U username -W < /the/path/to/sqlite-dumpfile.sql

Wenn die idSpalte "automatisch inkrementiert" werden soll, ändern Sie ihren Typ in der Tabellenerstellungszeile von "int" in "serial". PostgreSQL fügt dieser Spalte dann eine Sequenz hinzu, sodass INSERTs mit NULL-IDs automatisch der nächste verfügbare Wert zugewiesen wird. PostgreSQL erkennt auch keine AUTOINCREMENTBefehle, daher müssen diese entfernt werden.

Sie sollten auch nach datetimeSpalten im SQLite-Schema suchen und diese in timestampPostgreSQL ändern (danke an Clay für den Hinweis).

Wenn Sie Boolesche Werte in Ihrer SQLite haben, können Sie 1bzw. 0und 1::booleanbzw. konvertieren 0::booleanoder die boolesche Spalte im Schemaabschnitt des Speicherauszugs in eine Ganzzahl ändern und diese nach dem Import manuell in PostgreSQL korrigieren .

Wenn Ihre SQLite BLOBs enthält, möchten Sie das zu verwendende Schema anpassen bytea. Sie müssen wahrscheinlich auch einige decodeAnrufe einmischen . Das Schreiben eines schnellen und dreißigfachen Kopierers in Ihrer Lieblingssprache ist möglicherweise einfacher als das Zerlegen von SQL, wenn Sie jedoch mit vielen BLOBs zu tun haben.

Wenn Sie Fremdschlüssel haben, sollten Sie wie üblich wahrscheinlich nach set constraints all deferredProblemen beim Einfügen von Ordnungen suchen , indem Sie den Befehl in das BEGIN / COMMIT-Paar einfügen.

Vielen Dank an Nicolas Riley für die Booleschen, Blob- und Einschränkungsnotizen.

Wenn Sie `Code haben, der von einigen SQLite3-Clients generiert wurde, müssen Sie diese entfernen.

PostGRESQL erkennt auch keine unsignedSpalten. Möglicherweise möchten Sie diese löschen oder eine benutzerdefinierte Einschränkung wie die folgende hinzufügen:

CREATE TABLE tablename (
    ...
    unsigned_column_name integer CHECK (unsigned_column_name > 0)
);

Während SQLite standardmäßig Nullwerte verwendet '', müssen diese nach PostgreSQL als festgelegt werden NULL.

Die Syntax in der SQLite-Dump-Datei scheint größtenteils mit PostgreSQL kompatibel zu sein, sodass Sie einige Dinge patchen und füttern können psql. Das Importieren eines großen Datenstapels über SQL INSERTs kann eine Weile dauern, funktioniert jedoch.

mu ist zu kurz
quelle
4
Nein, Sie möchten die Transaktion beibehalten, um Overhead zu vermeiden.
Peter Eisentraut
3
Das funktioniert super. Ich würde auch beachten, dass Sie, wenn Sie SQLite- datetimeSpalten migrieren müssen, diese timestampfür Postgres ändern müssen.
Clay
4
Ein paar weitere Probleme, auf die ich gestoßen bin: Ändern BLOBin BYTEA( stackoverflow.com/questions/3103242 ), Ändern von 0/1 für BOOLEANSpalten in '0' / '1' und Verschieben von Einschränkungen ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Danke dafür. Ich habe dies einem Community-Wiki überlassen, da es sich zu einer Gruppenarbeit entwickelt hat. Fair ist fair.
Mu ist zu kurz
2
Sie können to_timestamp () in der postgreSQL verwenden, um einen Zeitstempel in einen progreSQL-Zeitstempel zu konvertieren
r03
61

pgloader

Ich bin auf diesen Beitrag gestoßen, als ich nach einer Möglichkeit gesucht habe, einen SQLite-Dump in PostgreSQL zu konvertieren. Obwohl dieser Beitrag eine akzeptierte Antwort hat (und eine gute dazu +1), halte ich das Hinzufügen für wichtig.

Ich begann hier nach Lösungen zu suchen und stellte fest, dass ich nach einer automatisierteren Methode suchte. Ich habe die Wiki-Dokumente nachgeschlagen:

https://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL

und entdeckt pgloader. Ziemlich coole Anwendung und relativ einfach zu bedienen. Sie können die flache SQLite-Datei in eine verwendbare PostgreSQL-Datenbank konvertieren. Ich habe von installiert *.debund eine commandDatei wie diese in einem Testverzeichnis erstellt:

load database  
    from 'db.sqlite3'  
    into postgresql:///testdb 
       
with include drop, create tables, create indexes, reset sequences  
         
set work_mem to '16MB', maintenance_work_mem to '512 MB';

wie die docs Zustand. Ich habe dann ein testdbmit erstellt createdb:

createdb testdb

Ich habe den pgloaderBefehl folgendermaßen ausgeführt:

pgloader command

und dann mit der neuen Datenbank verbunden:

psql testdb

Nach einigen Abfragen zur Überprüfung der Daten scheint es ziemlich gut funktioniert zu haben. Ich weiß, wenn ich versucht hätte, eines dieser Skripte auszuführen oder die hier erwähnte schrittweise Konvertierung durchzuführen, hätte ich viel mehr Zeit aufgewendet.

Um das Konzept zu beweisen, habe ich dies gelöscht testdbund in eine Entwicklungsumgebung auf einem Produktionsserver importiert und die Daten gut übertragen.

Nicorellius
quelle
2
Beachten Sie, dass (noch unterstützte) Ubuntu-Distributionen möglicherweise eine veraltete Version haben - v2.xy ist bereits veraltet und funktioniert nicht mehr. v3.2.x funktioniert möglicherweise, aber v3.2.3 wird empfohlen. Ich habe v3.2.3 von Bleeding Edge abgerufen und mit sudo dpkg -i <.deb Dateiname> installiert , es gab kein Problem mit Abhängigkeiten.
Silpol
Ich stimme @silpol zu - stellen Sie sicher, dass Sie die neueste stabile Version herunterladen und mit Ihrem bevorzugten Paketmanager installieren. Für die "Befehls" -Datei ist dies nur eine Textdatei mit dem Namen "Befehl" ohne Erweiterungsnamen (dh keine Notwendigkeit für .txt am Ende des Dateinamens). Sie müssen den Dateinamen nicht in eckige Klammern setzen. Ich musste den search_parth der psql-Datenbank ändern, um meine Daten zu sehen. pgloader funktioniert gut und ersparte mir viel Ärger
BKSpurgeon
das rette meinen Tag.
Yakob Ubaidi
1
Ja, ich hatte Probleme, als ich auf dieses Problem stieß, und dieses Tool hat es so einfach gemacht ... Manchmal funktionieren die Dinge einfach gut, nicht wahr?
Nicorellius
Dank bro. Ich sehe diese Antwort als die akzeptierte Antwort an! sehr gutes Werkzeug.
mohamed_18
12

Das Sequel Gem (eine Ruby-Bibliothek) bietet das Kopieren von Daten in verschiedene Datenbanken: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Installieren Sie zuerst Ruby und dann den Edelstein, indem Sie ihn ausführen gem install sequel.

Im Falle von SQLite wäre es so: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
quelle
1
Tolle Lösung. Viel einfacher als herumzuspielen pgloader.
Michaeldever
Absolut, pgloader ist chaotisch, der GC scheint auf riesigen Datenbanken abzustürzen: github.com/dimitri/pgloader/issues/962
hasufell
7

Sie können einen Einzeiler verwenden. Hier ein Beispiel mit Hilfe des Befehls sed:

sqlite3 mjsqlite.db .dump | sed -e 's/INTEGER PRIMARY KEY AUTOINCREMENT/SERIAL PRIMARY KEY/' | sed -e 's/PRAGMA foreign_keys=OFF;//' | sed -e 's/unsigned big int/BIGINT/g' | sed -e 's/UNSIGNED BIG INT/BIGINT/g' | sed -e 's/BIG INT/BIGINT/g' | sed -e 's/UNSIGNED INT(10)/BIGINT/' | sed -e 's/BOOLEAN/SMALLINT/g' | sed -e 's/boolean/SMALLINT/g' | sed -e 's/UNSIGNED BIG INT/INTEGER/g' | sed -e 's/INT(3)/INT2/g' | sed -e 's/DATETIME/TIMESTAMP/g' | psql mypqdb mypguser 
develCuy
quelle
Es gibt keinen Ersatz für LONG-Typ, zB
anderer Codierer
1
Ein weiterer Artikel könnte hinzugefügt werdensed -e 's/DATETIME/TIMESTAMP/g'
Silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - und für einen Vergleich aller Datentypen siehe stackoverflow.com/questions/1942586/…
Purplejacket
Ich hatte auch ein Problem mit einer SMALLINT, die im SQLite standardmäßig 't' oder 'f' war. Offensichtlich ein Boolescher Wert, aber mit keinem der DB-Systeme vertraut genug, um eine sichere Lösung zu empfehlen.
Labyrinth
1
Ersetzen ' | sed -e 'durch ; :)
AstraSerg
0

Ich habe versucht, den SQLite-Speicherauszug zu bearbeiten / neu zu drucken, damit PostgreSQL ihn akzeptiert. Er ist langwierig und fehleranfällig.

Was ich sehr schnell arbeiten musste:

Erstellen Sie zuerst das Schema unter PostgreSQL ohne Daten neu, indem Sie entweder den Speicherauszug bearbeiten oder wenn Sie ein ORM verwenden, haben Sie möglicherweise Glück und es spricht mit beiden Back-Ends (sqlalchemy, peewee, ...).

Migrieren Sie dann die Daten mit Pandas. Angenommen, Sie haben eine Tabelle mit einem Bool-Feld (das in SQLite 0/1 ist, in PostgreSQL jedoch t / f sein muss).

def int_to_strbool(df, column):
    df = df.replace({column: 0}, 'f')
    df = df.replace({column: 1}, 't')
    return df

#def other_transform(df, column):
#...

conn = sqlite3.connect(db)
df = pd.read_sql(f'select * from {table_name}', conn)

df = int_to_strbool(df, bool_column_name)
#df = other_transform(df, other_column_name)

df.to_csv(table_name + '.csv'), sep=',', header=False, index=False)

Dies funktioniert wie ein Zauber, ist einfach zu schreiben, zu lesen und zu debuggen, im Gegensatz zu (für mich) den regulären Ausdrücken.

Jetzt können Sie versuchen, die resultierende CSV mit PostgreSQL zu laden (auch grafisch mit dem Admin-Tool), mit der einzigen Einschränkung, dass Sie die Tabellen mit Fremdschlüsseln laden müssen, nachdem Sie die Tabellen mit den entsprechenden Quellschlüsseln geladen haben. Ich hatte nicht den Fall einer zirkulären Abhängigkeit, ich denke, Sie können die Schlüsselprüfung vorübergehend aussetzen, wenn dies der Fall ist.

Agomcas
quelle
-1

pgloader wirkt Wunder bei der Konvertierung von Datenbanken in SQLite in Postgresql.

Hier ist ein Beispiel für die Konvertierung eines lokalen sqlitedb in eine entfernte PostgreSQL-Datenbank:

pgloader sqlite.db postgresql: // Benutzername : Passwort @ Hostname / Datenbankname

Kouichi
quelle
1
Pgloader ist furchtbar fehlerhaft und unzuverlässig. Es stürzt sofort mit dem Fehler abKABOOM! Control stack exhausted (no more space for function call frames).
Cerin