Convertir archivo de volcado SQL de SQLITE a POSTGRESQL

96

He estado haciendo desarrollo usando la base de datos SQLITE con producción en POSTGRESQL. Acabo de actualizar mi base de datos local con una gran cantidad de datos y necesito transferir una tabla específica a la base de datos de producción.

Según la ejecución sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE genera un volcado de tabla en el siguiente 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;

¿Cómo convierto lo anterior en un archivo de volcado compatible con POSTGRESQL que puedo importar a mi servidor de producción?

DevX
fuente
1
Bueno, ese comando no funcionó para mí hasta que cambié sqlite a sqlite3
Celal Ergün

Respuestas:

101

Debería poder introducir ese archivo de volcado directamente en psql:

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

Si desea que la idcolumna se "incremente automáticamente", cambie su tipo de "int" a "serial" en la línea de creación de la tabla. Posteriormente, PostgreSQL adjuntará una secuencia a esa columna para que a los INSERTs con ID NULL se les asigne automáticamente el siguiente valor disponible. PostgreSQL tampoco reconocerá los AUTOINCREMENTcomandos, por lo que estos deben eliminarse.

También querrá buscar datetimecolumnas en el esquema SQLite y cambiarlas a timestampPostgreSQL (gracias a Clay por señalar esto).

Si tiene valores booleanos en su SQLite, puede convertir 1y 0y 1::booleany 0::boolean(respectivamente) o puede cambiar la columna booleana a un número entero en la sección de esquema del volcado y luego arreglarlos a mano dentro de PostgreSQL después de la importación.

Si tiene BLOB en su SQLite, entonces querrá ajustar el esquema para usar bytea. Probablemente también necesitará mezclar algunas decodellamadas . Escribir una copiadora rápida y sucia en su idioma favorito podría ser más fácil que alterar el SQL si tiene muchos BLOB con los que lidiar.

Como de costumbre, si tiene claves foráneas, probablemente querrá investigar set constraints all deferredpara evitar problemas de orden de inserción, colocando el comando dentro del par BEGIN / COMMIT.

Gracias a Nicolas Riley por las notas booleanas, blob y de restricciones.

Si tiene `en su código, tal como lo generan algunos clientes SQLite3, debe eliminarlos.

PostGRESQL tampoco reconoce unsignedcolumnas, es posible que desee eliminar eso o agregar una restricción personalizada como esta:

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

Si bien SQLite establece los valores nulos de forma predeterminada en '', PostgreSQL requiere que se establezcan como NULL.

La sintaxis en el archivo de volcado de SQLite parece ser mayormente compatible con PostgreSQL, por lo que puede parchear algunas cosas y alimentarlas psql. Importar una gran cantidad de datos a través de SQL INSERT puede llevar un tiempo, pero funcionará.

mu es demasiado corto
fuente
4
No, desea conservar la transacción para evitar algunos gastos generales.
Peter Eisentraut
3
Esto funciona muy bien. También me gustaría señalar que si necesita migrar datetimecolumnas sqlite , debe cambiarlas a timestamppara postgres.
Clay
4
Me encontré con algunos problemas más: cambiar BLOBa BYTEA( stackoverflow.com/questions/3103242 ), cambiar 0/1 para las BOOLEANcolumnas a '0' / '1' y diferir las restricciones ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Gracias por eso. Le entregué esto a una wiki de la comunidad ya que se ha convertido en un esfuerzo grupal, lo justo es lo justo.
mu es demasiado corto
2
Puede usar to_timestamp () en postgreSQL para convertir una marca de tiempo en una marca de tiempo
progreSQL
61

pgloader

Encontré esta publicación cuando buscaba una forma de convertir un volcado de SQLite a PostgreSQL. Aunque esta publicación tiene una respuesta aceptada (y una buena en ese +1), creo que agregar esto es importante.

Comencé a buscar soluciones aquí y me di cuenta de que estaba buscando un método más automatizado. Busqué los documentos de la wiki:

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

y descubierto pgloader. Una aplicación muy buena y relativamente fácil de usar. Puede convertir el archivo SQLite plano en una base de datos PostgreSQL utilizable. Instalé desde *.deby creé un commandarchivo como este en un directorio de prueba:

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

como el estado de docs . Luego creé un testdbcon createdb:

createdb testdb

Ejecuté el pgloadercomando así:

pgloader command

y luego conectado a la nueva base de datos:

psql testdb

Después de algunas consultas para verificar los datos, parece que funcionó bastante bien. Sé que si hubiera intentado ejecutar uno de estos scripts o hacer la conversión paso a paso mencionada aquí, habría pasado mucho más tiempo.

Para probar el concepto, descargué esto testdby lo importé a un entorno de desarrollo en un servidor de producción y los datos se transfirieron muy bien.

nicorellius
fuente
2
Tenga en cuenta que las distribuciones de Ubuntu (aún admitidas) pueden tener una versión desactualizada: v2.xy ya está obsoleto y en realidad no funciona. v3.2.x podría funcionar, pero se recomienda v3.2.3. Obtuve v3.2.3 de la vanguardia y lo instalé con sudo dpkg -i <nombre de archivo .deb> , no tuvo ningún problema con las dependencias.
silpol
Estoy de acuerdo con @silpol: asegúrese de descargar la última versión estable e instalarla usando su administrador de paquetes favorito; para el archivo "comando", este es solo un archivo de texto llamado 'comando' sin nombre de extensión (es decir, no es necesario .txt al final del nombre del archivo). No es necesario poner el nombre del archivo entre corchetes angulares; tuve que cambiar la parte de búsqueda de la base de datos psql para ver mis datos; pgloader funciona bien y me ahorró una gran cantidad de problemas
BKSpurgeon
esto salva mi día.
Yakob Ubaidi
1
Sí, estaba luchando cuando me encontré con este problema, y ​​esa herramienta lo hizo tan fácil ... A veces las cosas simplemente funcionan bien, ¿no?
nicorellius
Gracias hermano. ¡Veo que esta respuesta vale la pena ser la respuesta aceptada! muy buena herramienta.
mohamed_18
12

La secuela de gemas (una biblioteca Ruby) ofrece copia de datos en diferentes bases de datos: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Primero instale Ruby, luego instale la gema ejecutando gem install sequel.

En el caso de sqlite, sería así: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
fuente
1
Solución impresionante. Mucho más fácil que jugar con él pgloader.
Michaeldever
Absolutamente, pgloader es complicado, el GC parece fallar en bases de datos enormes: github.com/dimitri/pgloader/issues/962
hasufell
7

Puede usar un trazador de líneas, aquí hay un ejemplo con la ayuda 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 
develCuy
fuente
no hay reemplazo para el tipo LONG, por ejemplo
yetanothercoder
1
se podría agregar un elemento mássed -e 's/DATETIME/TIMESTAMP/g'
silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - y para una comparación de todos los tipos de datos, consulte stackoverflow.com/questions/1942586/…
Purplejacket
También tuve un problema con un SMALLINT que estaba predeterminado en 't' o 'f' en sqlite. Obviamente, un booleano, pero no lo suficientemente familiarizado con ninguno de los sistemas de base de datos para recomendar una solución segura.
laberinto
1
Reemplazar ' | sed -e 'con ; :)
AstraSerg
0

He intentado editar / regexping el volcado de sqlite para que PostgreSQL lo acepte, es tedioso y propenso a errores.

Lo que llegué a trabajar realmente rápido:

Primero vuelva a crear el esquema en PostgreSQL sin ningún dato, ya sea editando el volcado o si estaba usando un ORM, puede tener suerte y se comunica con ambos back-end (sqlalchemy, peewee, ...).

Luego, migre los datos usando pandas. Suponga que tiene una tabla con un campo bool (que es 0/1 en sqlite, pero debe ser t / f en 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)

Esto funciona como un encanto, es fácil de escribir, leer y depurar cada función, a diferencia (para mí) de las expresiones regulares.

Ahora puede intentar cargar el csv resultante con PostgreSQL (incluso gráficamente con la herramienta de administración), con la única advertencia de que debe cargar las tablas con claves externas después de haber cargado las tablas con las claves de origen correspondientes. No tuve el caso de una dependencia circular, supongo que puede suspender temporalmente la verificación de claves si ese es el caso.

agomcas
fuente
-1

pgloader hace maravillas en la conversión de base de datos en sqlite a postgresql.

Aquí hay un ejemplo sobre cómo convertir un sqlitedb local en un db PostgreSQL remoto:

pgloader sqlite.db postgresql: // nombre de usuario : contraseña @ nombre de host / dbname

kouichi
fuente
1
Pgloader tiene muchos errores y no es confiable. Inmediatamente se bloquea con el errorKABOOM! Control stack exhausted (no more space for function call frames).
Cerin