Convertir le fichier de vidage SQLITE SQL en POSTGRESQL

96

J'ai fait du développement en utilisant la base de données SQLITE avec une production en POSTGRESQL. Je viens de mettre à jour ma base de données locale avec une énorme quantité de données et j'ai besoin de transférer une table spécifique vers la base de données de production.

En fonction de l'exécution sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE génère un vidage de table au format suivant:

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;

Comment convertir ce qui précède en un fichier de vidage compatible POSTGRESQL que je peux importer dans mon serveur de production?

DevX
la source
1
Eh bien, cette commande n'a pas fonctionné pour moi jusqu'à ce que je change de sqlite en sqlite3
Celal Ergün

Réponses:

101

Vous devriez pouvoir alimenter ce fichier de vidage directement dans psql:

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

Si vous voulez que la idcolonne "s'incrémente automatiquement", changez son type de "int" à "serial" dans la ligne de création de table. PostgreSQL attachera ensuite une séquence à cette colonne afin que les INSERT avec des identifiants NULL soient automatiquement affectés à la prochaine valeur disponible. PostgreSQL ne reconnaîtra pas non plus les AUTOINCREMENTcommandes, elles doivent donc être supprimées.

Vous voudrez également vérifier les datetimecolonnes dans le schéma SQLite et les changer timestamppour PostgreSQL (merci à Clay pour l'avoir signalé).

Si vous avez booléens dans votre SQLite, vous pouvez convertir 1et 0et 1::booleanet 0::boolean(respectivement) ou vous pouvez changer la colonne booléenne à un nombre entier dans la section de schéma de la décharge, puis les réparer manuellement dans PostgreSQL après l'importation.

Si vous avez des BLOB dans votre SQLite, vous voudrez ajuster le schéma à utiliser bytea. Vous devrez probablement également mélanger certains decodeappels . Ecrire un copieur quick'n'dirty dans votre langue préférée pourrait être plus facile que de modifier le SQL si vous avez beaucoup de BLOB à gérer.

Comme d'habitude, si vous avez des clés étrangères, vous voudrez probablement examiner set constraints all deferredpour éviter les problèmes de commande d'insertion, en plaçant la commande à l'intérieur de la paire BEGIN / COMMIT.

Merci à Nicolas Riley pour les notes booléennes, blob et contraintes.

Si vous avez `sur votre code, tel que généré par certains clients SQLite3, vous devez les supprimer.

PostGRESQL ne reconnaît pas non plus les unsignedcolonnes, vous voudrez peut-être les supprimer ou ajouter une contrainte personnalisée telle que celle-ci:

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

Alors que SQLite ''définit par défaut les valeurs nulles sur , PostgreSQL exige qu'elles soient définies comme NULL.

La syntaxe du fichier de vidage SQLite semble être principalement compatible avec PostgreSQL, vous pouvez donc patcher quelques éléments et les alimenter psql. L'importation d'une grande pile de données via SQL INSERT peut prendre un certain temps, mais cela fonctionnera.

mu est trop court
la source
4
Non, vous souhaitez conserver la transaction pour éviter des frais généraux.
Peter Eisentraut
3
Cela fonctionne très bien. Je noterais également que si vous avez besoin de migrer des datetimecolonnes sqlite , vous devez les changer en timestamppour postgres.
Clay
4
Quelques problèmes supplémentaires que j'ai rencontrés: changer BLOBdans BYTEA( stackoverflow.com/questions/3103242 ), changer 0/1 pour les BOOLEANcolonnes en '0' / '1' et reporter les contraintes ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Merci pour ça. J'ai donné cela à un wiki communautaire car il s'est transformé en effort de groupe, juste est juste.
mu est trop court le
2
Vous pouvez utiliser to_timestamp () dans le postgreSQL pour convertir un horodatage en un horodatage
progreSQL
61

pgloader

Je suis tombé sur cet article lors de la recherche d'un moyen de convertir un dump SQLite en PostgreSQL. Même si cet article a une réponse acceptée (et une bonne réponse à +1), je pense que l'ajout de cela est important.

J'ai commencé à chercher des solutions ici et j'ai réalisé que je cherchais une méthode plus automatisée. J'ai recherché les documents du wiki:

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

et découvert pgloader. Application assez cool et relativement facile à utiliser. Vous pouvez convertir le fichier SQLite plat en une base de données PostgreSQL utilisable. J'ai installé à partir du *.debet créé un commandfichier comme celui-ci dans un répertoire de 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';

comme l' état de la documentation . J'ai ensuite créé un testdbavec createdb:

createdb testdb

J'ai exécuté la pgloadercommande comme ceci:

pgloader command

puis connecté à la nouvelle base de données:

psql testdb

Après quelques requêtes pour vérifier les données, il semble que cela a plutôt bien fonctionné. Je sais que si j'avais essayé d'exécuter l'un de ces scripts ou de faire la conversion par étapes mentionnée ici, j'aurais passé beaucoup plus de temps.

Pour prouver le concept, j'ai jeté ceci testdbet importé dans un environnement de développement sur un serveur de production et les données transférées bien.

Nicorellius
la source
2
Attention, les distributions Ubuntu (toujours prises en charge) peuvent avoir une version obsolète - v2.xy est déjà obsolète et ne fonctionne pas réellement. La v3.2.x peut fonctionner mais la v3.2.3 est recommandée. J'ai récupéré la v3.2.3 à partir de la pointe de la technologie et installé avec sudo dpkg -i <nom de fichier .deb> , cela n'a eu aucun problème avec les dépendances.
silpol
Je suis d'accord avec @silpol - assurez-vous de télécharger la dernière version stable et de l'installer en utilisant votre gestionnaire de paquets fav; pour le fichier "commande", il s'agit simplement d'un fichier texte appelé "commande" sans nom d'extension (c'est-à-dire pas besoin de .txt à la fin du nom de fichier), vous n'avez pas besoin de mettre le nom du fichier entre crochets angulaires; j'ai dû changer le search_parth de la base de données psql afin de voir mes données; pgloader fonctionne bien et m'a évité beaucoup de tracas
BKSpurgeon
cela sauve ma journée.
Yakob Ubaidi
1
Ouais, j'avais du mal quand j'ai rencontré ce problème, et cet outil a rendu les choses si faciles ... Parfois, les choses se passent bien, n'est-ce pas?
nicorellius
Merci mec. Je vois que cette réponse vaut la peine d'être la réponse acceptée! très bon outil.
mohamed_18
16

J'ai écrit un script pour faire le sqlite3à la postgresmigration. Il ne gère pas toutes les traductions de schéma / données mentionnées dans https://stackoverflow.com/a/4581921/1303625 , mais il fait ce dont j'avais besoin. Espérons que ce sera un bon point de départ pour les autres.

https://gist.github.com/2253099

Earle Clubb
la source
2
Cela fonctionne bien! J'ai bifurqué l'essentiel et ajouté quelques informations en tant que commentaire: gist.github.com/bittner/7368128
Peterino
12

Le gem suite (une bibliothèque Ruby) propose la copie de données dans différentes bases de données: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Installez d'abord Ruby, puis installez le gem en exécutant gem install sequel.

Dans le cas de sqlite, ce serait comme ceci: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
la source
1
Solution géniale. Beaucoup plus facile que de jouer avec pgloader.
michaeldever
Absolument, pgloader est en désordre, le GC semble planter sur d'énormes bases de données: github.com/dimitri/pgloader/issues/962
hasufell
7

Vous pouvez utiliser une ligne unique, voici un exemple à l'aide de la commande 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
la source
il n'y a pas de remplacement pour le type LONG, par exemple
yetanothercoder
1
un article de plus pourrait être ajoutésed -e 's/DATETIME/TIMESTAMP/g'
silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - et pour une comparaison de tous les types de données, voir stackoverflow.com/questions/1942586/…
Purplejacket
J'ai également eu un problème avec un SMALLINT qui par défaut était «t» ou «f» dans le sqlite. De toute évidence, un booléen, mais pas assez familier avec l'un ou l'autre des systèmes de base de données pour recommander une solution sûre.
labyrinthe
1
Remplacer ' | sed -e 'par ; :)
AstraSerg
0

J'ai essayé de modifier / regexping le vidage sqlite pour que PostgreSQL l'accepte, il est fastidieux et sujet aux erreurs.

Ce que j'ai obtenu pour travailler très vite:

Commencez par recréer le schéma sur PostgreSQL sans aucune donnée, que ce soit en éditant le vidage ou si vous utilisiez un ORM, vous aurez peut-être de la chance et il parle aux deux back-ends (sqlalchemy, peewee, ...).

Puis migrez les données à l'aide de pandas. Supposons que vous ayez une table avec un champ booléen (qui vaut 0/1 dans sqlite, mais doit être t / f dans 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)

Cela fonctionne comme un charme, est facile à écrire, lire et déboguer chaque fonction, contrairement (pour moi) aux expressions régulières.

Vous pouvez maintenant essayer de charger le csv résultant avec PostgreSQL (même graphiquement avec l'outil d'administration), avec la seule mise en garde que vous devez charger les tables avec des clés étrangères après avoir chargé les tables avec les clés source correspondantes. Je n'avais pas le cas d'une dépendance circulaire, je suppose que vous pouvez suspendre temporairement la vérification de la clé si tel est le cas.

agomcas
la source
-1

pgloader fait des merveilles sur la conversion de la base de données de sqlite en postgresql.

Voici un exemple de conversion d'un sqlitedb local en une base de données PostgreSQL distante:

pgloader sqlite.db postgresql: // username : password @ hostname / dbname

Kouichi
la source
1
Pgloader est terriblement bogué et peu fiable. Il plante immédiatement avec l'erreurKABOOM! Control stack exhausted (no more space for function call frames).
Cerin