Converti il ​​file dump SQLITE SQL in POSTGRESQL


96

Ho fatto sviluppo utilizzando database SQLITE con produzione in POSTGRESQL. Ho appena aggiornato il mio database locale con un'enorme quantità di dati e ho bisogno di trasferire una tabella specifica al database di produzione.

In base all'esecuzione sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE restituisce un dump della tabella nel seguente formato:

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;

Come posso convertire quanto sopra in un file di dump compatibile con POSTGRESQL che posso importare nel mio server di produzione?


1
Bene, quel comando non ha funzionato per me fino a quando non ho cambiato sqlite in sqlite3
Celal Ergün

Risposte:


101

Dovresti essere in grado di inserire il file di dump direttamente in psql:

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

Se vuoi che la idcolonna venga "incrementata automaticamente", cambia il suo tipo da "int" a "seriale" nella riga di creazione della tabella. PostgreSQL allegherà quindi una sequenza a quella colonna in modo che agli INSERT con ID NULL venga automaticamente assegnato il successivo valore disponibile. Anche PostgreSQL non riconoscerà i AUTOINCREMENTcomandi, quindi è necessario rimuoverli.

Dovrai anche controllare le datetimecolonne nello schema SQLite e cambiarle in timestampPostgreSQL (grazie a Clay per averlo sottolineato).

Se si dispone di booleani in SQLite, allora è possibile convertire 1e 0ed 1::booleane 0::boolean(rispettivamente) o si può cambiare la colonna booleana in un intero nella sezione schema della discarica e poi fissarli a mano all'interno PostgreSQL dopo l'importazione.

Se hai BLOB nel tuo SQLite, ti consigliamo di regolare lo schema da utilizzare bytea. Probabilmente avrai anche bisogno di unire alcune decodechiamate . Scrivere una copiatrice veloce e sporca nella tua lingua preferita potrebbe essere più facile che alterare l'SQL se hai molti BLOB da gestire.

Come al solito, se hai chiavi esterne, probabilmente vorrai esaminare set constraints all deferredper evitare problemi di ordinamento dell'inserimento, inserendo il comando all'interno della coppia BEGIN / COMMIT.

Grazie a Nicolas Riley per le note booleane, blob e dei vincoli.

Se hai `sul tuo codice, come generato da alcuni client SQLite3, devi rimuoverli.

PostGRESQL inoltre non riconosce le unsignedcolonne, potresti volerlo eliminare o aggiungere un vincolo personalizzato come questo:

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

Mentre SQLite imposta i valori null di default su '', PostgreSQL richiede che siano impostati come NULL.

La sintassi nel file di dump SQLite sembra essere per lo più compatibile con PostgreSQL, quindi puoi correggere alcune cose e darle in pasto psql. L'importazione di una grande pila di dati tramite SQL INSERT potrebbe richiedere del tempo, ma funzionerà.


4
No, vuoi mantenere la transazione per evitare un sovraccarico.
Peter Eisentraut

3
Funziona alla grande. Vorrei anche notare che se è necessario migrare datetimecolonne sqlite , è necessario cambiarle in timestamppostgres.
Clay

4
Alcuni altri problemi che ho riscontrato: modifica BLOBin BYTEA( stackoverflow.com/questions/3103242 ), modifica di 0/1 per le BOOLEANcolonne in "0" / "1" e rinvio dei vincoli ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley

1
@NicholasRiley: Grazie per questo. L'ho lasciato a un wiki della comunità poiché si è trasformato in uno sforzo di gruppo, giusto è giusto.
mu è troppo corto

2
Puoi usare to_timestamp () in postgreSQL per convertire un timestamp in un timestamp
progreSQL

61

pgloader

Mi sono imbattuto in questo post mentre cercavo un modo per convertire un dump SQLite in PostgreSQL. Anche se questo post ha una risposta accettata (e una buona in quel +1), penso che aggiungerla sia importante.

Ho iniziato a esaminare le soluzioni qui e mi sono reso conto che stavo cercando un metodo più automatizzato. Ho cercato i documenti wiki:

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

e scoperto pgloader. Applicazione piuttosto interessante ed è relativamente facile da usare. Puoi convertire il file flat SQLite in un database PostgreSQL utilizzabile. Ho installato da *.debe creato un commandfile come questo in una directory di test:

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';

come lo stato dei documenti . Ho quindi creato un testdbcon createdb:

createdb testdb

Ho eseguito il pgloadercomando in questo modo:

pgloader command

e poi connesso al nuovo database:

psql testdb

Dopo alcune domande per controllare i dati, sembra che abbia funzionato abbastanza bene. So che se avessi provato a eseguire uno di questi script o a eseguire la conversione graduale menzionata qui, avrei trascorso molto più tempo.

Per dimostrare il concetto ho scaricato questo testdbe importato in un ambiente di sviluppo su un server di produzione ei dati trasferiti correttamente.


2
Fai attenzione che (ancora supportate) le distribuzioni di Ubuntu potrebbero avere una versione obsoleta: v2.xy è già deprecata e in realtà non funziona. v3.2.x potrebbe funzionare ma si consiglia v3.2.3. Ho recuperato la v3.2.3 da Bleeding Edge e l'ho installato con sudo dpkg -i <.deb file name> , non ha avuto problemi con le dipendenze.
silpol

Sono d'accordo con @silpol - assicurati di scaricare l'ultima versione stabile e installarla usando il tuo gestore di pacchetti fav; per il file "comando" questo è solo un file di testo chiamato 'comando' senza nome di estensione (cioè non c'è bisogno di .txt alla fine del nome del file) non è necessario mettere il nome del file tra parentesi angolari; ho dovuto cambiare search_parth del database psql per vedere i miei dati; pgloader funziona bene e mi ha salvato una grande quantità di seccature
BKSpurgeon

questo salva la mia giornata.
Yakob Ubaidi

1
Sì, stavo lottando quando ho riscontrato questo problema, e quello strumento lo ha reso così facile ... A volte le cose funzionano bene, no?
nicorellius

Grazie fratello. Vedo che questa risposta vale la pena essere la risposta accettata! ottimo strumento.
mohamed_18


12

La gemma sequel (una libreria Ruby) offre la copia dei dati su diversi database: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Prima installa Ruby, quindi installa la gemma eseguendo gem install sequel.

In caso di sqlite, sarebbe come questo: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db


1
Ottima soluzione. Molto più facile che giocherellare con pgloader.
michaeldever

Assolutamente, pgloader è disordinato, il GC sembra bloccarsi su enormi database: github.com/dimitri/pgloader/issues/962
hasufell

7

Puoi usare una riga, ecco un esempio con l'aiuto del comando 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 

non è possibile sostituire il tipo LONG, ad esempio
codificatore

1
un altro elemento potrebbe essere aggiuntosed -e 's/DATETIME/TIMESTAMP/g'
silpol

sed -e 's/TINYINT(1)/SMALLINT/g' - e per un confronto di tutti i tipi di dati vedono stackoverflow.com/questions/1942586/...
Purplejacket

Ho anche avuto un problema con un SMALLINT che di default era "t" o "f" in sqlite. Ovviamente un booleano, ma non abbastanza familiare con nessuno dei due sistemi db per consigliare una soluzione sicura.
labirinto

1
Sostituisci ' | sed -e 'con ; :)
AstraSerg

0

Ho provato a modificare / regexizzare il dump sqlite in modo che PostgreSQL lo accetti, è noioso e soggetto a errori.

Quello che ho avuto modo di lavorare molto velocemente:

Per prima cosa ricrea lo schema su PostgreSQL senza alcun dato, modificando il dump o se stavi usando un ORM potresti essere fortunato e parla con entrambi i back-end (sqlalchemy, peewee, ...).

Quindi migrare i dati utilizzando i panda. Supponi di avere una tabella con un campo bool (che è 0/1 in sqlite, ma deve essere t / f in PostgreSQL)

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)

Funziona a meraviglia, è facile scrivere, leggere ed eseguire il debug di ogni funzione, a differenza (per me) delle espressioni regolari.

Ora puoi provare a caricare il csv risultante con PostgreSQL (anche graficamente con lo strumento di amministrazione), con l'unico avvertimento che devi caricare le tabelle con chiavi esterne dopo aver caricato le tabelle con le chiavi sorgente corrispondenti. Non ho avuto il caso di una dipendenza circolare, immagino che tu possa sospendere temporaneamente il controllo della chiave se è così.


-1

pgloader fa miracoli sulla conversione del database da sqlite a postgresql.

Ecco un esempio sulla conversione di un sqlitedb locale in un database PostgreSQL remoto:

pgloader sqlite.db postgresql: // nomeutente : password @ nomehost / nome db


1
Pgloader è terribilmente buggato e inaffidabile. Si blocca immediatamente con l'erroreKABOOM! Control stack exhausted (no more space for function call frames).
Cerin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.