¿Manera rápida y fácil de migrar SQLite3 a MySQL?

¿Alguien sabe una forma rápida y sencilla de migrar una base de datos SQLite3 a MySQL?

Aquí hay una lista de convertidores (no actualizada desde 2011):


Un método alternativo que funcionaría muy bien, pero que rara vez se menciona es: use una clase ORM que abstraiga las diferencias específicas de la base de datos para usted. por ejemplo, obtienes estos en PHP ( RedBean ), Python (capa ORM de Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )

es decir, podrías hacer esto:

  1. Cargue los datos de la base de datos de origen utilizando la clase ORM.
  2. Almacene los datos en la memoria o serialícelos en el disco.
  3. Almacene los datos en la base de datos de destino utilizando la clase ORM.

Todo el mundo parece comenzar con algunas expresiones gregarias y perl y, por lo tanto, obtienes algo que funciona para tu conjunto de datos particular, pero no tienes idea si se importaron los datos correctamente o no. Estoy muy sorprendido de que nadie haya construido una biblioteca sólida que pueda convertir entre los dos.

Aquí una lista de TODAS las diferencias en la syntax de SQL que conozco entre los dos formatos de archivo: Las líneas que comienzan con:

  • COMIENZA LA TRANSACCIÓN
  • COMETER
  • sqlite_sequence
  • CREAR ÍNDICE ÚNICO

no se usan en MySQL

  • SQLlite usa CREATE TABLE / INSERT INTO “table_name” y MySQL usa CREATE TABLE / INSERT INTO table_name
  • MySQL no usa comillas dentro de la definición del esquema
  • MySQL utiliza comillas simples para cadenas dentro de las cláusulas INSERT INTO
  • SQLlite y MySQL tienen diferentes formas de escapar de cadenas dentro de las cláusulas INSERT INTO
  • SQLlite usa ‘t’ y ‘f’ para booleanos, MySQL usa 1 y 0 (una expresión regular simple para esto puede fallar cuando tienes una cadena como: ‘Sí, no lo tienes dentro de INSERT INTO)
  • SQLLite utiliza AUTOINCREMENT, MySQL usa AUTO_INCREMENT

Aquí hay una secuencia de comandos de perl pirateada muy básica que funciona para mi conjunto de datos y comprueba muchas más de estas condiciones que otras secuencias de comandos de Perl que encontré en la web. Nu garantiza que funcionará para sus datos, pero siéntase libre de modificar y publicar aquí.

#! /usr/bin/perl while ($line = <>){ if (($line !~ /BEGIN TRANSACTION/) && ($line !~ /COMMIT/) && ($line !~ /sqlite_sequence/) && ($line !~ /CREATE UNIQUE INDEX/)){ if ($line =~ /CREATE TABLE \"([a-z_]*)\"(.*)/){ $name = $1; $sub = $2; $sub =~ s/\"//g; $line = "DROP TABLE IF EXISTS $name;\nCREATE TABLE IF NOT EXISTS $name$sub\n"; } elsif ($line =~ /INSERT INTO \"([a-z_]*)\"(.*)/){ $line = "INSERT INTO $1$2\n"; $line =~ s/\"/\\\"/g; $line =~ s/\"/\'/g; }else{ $line =~ s/\'\'/\\\'/g; } $line =~ s/([^\\'])\'t\'(.)/$1THIS_IS_TRUE$2/g; $line =~ s/THIS_IS_TRUE/1/g; $line =~ s/([^\\'])\'f\'(.)/$1THIS_IS_FALSE$2/g; $line =~ s/THIS_IS_FALSE/0/g; $line =~ s/AUTOINCREMENT/AUTO_INCREMENT/g; print $line; } } 

Aquí hay un script de Python, creado a partir de la respuesta de Shalmanese y algo de ayuda de Alex Martelli en Translating Perl to Python

Lo estoy convirtiendo en wiki comunitario, así que siéntete libre de editar y refactorizar siempre que no rompa la funcionalidad (afortunadamente podemos retroceder) – Es bastante feo pero funciona

use como tal (suponiendo que el script se llama dump_for_mysql.py :

 sqlite3 sample.db .dump | python dump_for_mysql.py > dump.sql 

Que luego puedes importar a mysql

nota: necesita agregar restricciones de clave externa manualmente ya que sqlite en realidad no las admite

aquí está el guión:

 #!/usr/bin/env python import re import fileinput def this_line_is_useless(line): useless_es = [ 'BEGIN TRANSACTION', 'COMMIT', 'sqlite_sequence', 'CREATE UNIQUE INDEX', 'PRAGMA foreign_keys=OFF', ] for useless in useless_es: if re.search(useless, line): return True def has_primary_key(line): return bool(re.search(r'PRIMARY KEY', line)) searching_for_end = False for line in fileinput.input(): if this_line_is_useless(line): continue # this line was necessary because ''); # would be converted to \'); which isn't appropriate if re.match(r".*, ''\);", line): line = re.sub(r"''\);", r'``);', line) if re.match(r'^CREATE TABLE.*', line): searching_for_end = True m = re.search('CREATE TABLE "?(\w*)"?(.*)', line) if m: name, sub = m.groups() line = "DROP TABLE IF EXISTS %(name)s;\nCREATE TABLE IF NOT EXISTS `%(name)s`%(sub)s\n" line = line % dict(name=name, sub=sub) else: m = re.search('INSERT INTO "(\w*)"(.*)', line) if m: line = 'INSERT INTO %s%s\n' % m.groups() line = line.replace('"', r'\"') line = line.replace('"', "'") line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line) line = line.replace('THIS_IS_TRUE', '1') line = re.sub(r"([^'])'f'(.)", "\1THIS_IS_FALSE\2", line) line = line.replace('THIS_IS_FALSE', '0') # Add auto_increment if it is not there since sqlite auto_increments ALL # primary keys if searching_for_end: if re.search(r"integer(?:\s+\w+)*\s*PRIMARY KEY(?:\s+\w+)*\s*,", line): line = line.replace("PRIMARY KEY", "PRIMARY KEY AUTO_INCREMENT") # replace " and ' with ` because mysql doesn't like quotes in CREATE commands if line.find('DEFAULT') == -1: line = line.replace(r'"', r'`').replace(r"'", r'`') else: parts = line.split('DEFAULT') parts[0] = parts[0].replace(r'"', r'`').replace(r"'", r'`') line = 'DEFAULT'.join(parts) # And now we convert it back (see above) if re.match(r".*, ``\);", line): line = re.sub(r'``\);', r"'');", line) if searching_for_end and re.match(r'.*\);', line): searching_for_end = False if re.match(r"CREATE INDEX", line): line = re.sub('"', '`', line) if re.match(r"AUTOINCREMENT", line): line = re.sub("AUTOINCREMENT", "AUTO_INCREMENT", line) print line, 

Es complicado porque los archivos de volcado son específicos del proveedor de la base de datos.

Si está utilizando Rails, existe un gran complemento para esto. Leer: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/

Actualizar

Bifurcación mantenida actualmente: https://github.com/ludicast/yaml_db

Sorprendido, nadie ha mencionado esto por ahora, pero en realidad hay una herramienta explícita para esto. Está en perl, SQL: Traductor: http://sqlfairy.sourceforge.net/

Convierte entre casi cualquier forma de datos tabulares (diferentes formatos de SQL, hoja de cálculo de Excel), e incluso hace diagtwigs de su esquema de SQL.

 aptitude install sqlfairy libdbd-sqlite3-perl sqlt -f DBI --dsn dbi:SQLite:../.open-tran/ten-sq.db -t MySQL --add-drop-table > mysql-ten-sq.sql sqlt -f DBI --dsn dbi:SQLite:../.open-tran/ten-sq.db -t Dumper --use-same-auth > sqlite2mysql-dumper.pl chmod +x sqlite2mysql-dumper.pl ./sqlite2mysql-dumper.pl --help ./sqlite2mysql-dumper.pl --add-truncate --mysql-loadfile > mysql-dump.sql sed -e 's/LOAD DATA INFILE/LOAD DATA LOCAL INFILE/' -i mysql-dump.sql echo 'drop database `ten-sq`' | mysql -p -u root echo 'create database `ten-sq` charset utf8' | mysql -p -u root mysql -p -u root -D ten-sq < mysql-ten-sq.sql mysql -p -u root -D ten-sq < mysql-dump.sql 

Acabo de pasar por este proceso, y hay mucha ayuda e información muy buena en este Q / A, pero descubrí que tenía que unir varios elementos (más algunos de otras preguntas y respuestas) para obtener una solución de trabajo en para migrar exitosamente

Sin embargo, incluso después de combinar las respuestas existentes, encontré que la secuencia de comandos de Python no funcionaba completamente para mí, ya que no funcionaba donde había múltiples ocurrencias booleanas en un INSERT. Vea aquí por qué fue ese el caso.

Entonces, pensé en publicar mi respuesta fusionada aquí. El crédito va a aquellos que han contribuido en otros lugares, por supuesto. Pero quería devolver algo, y ahorrar a los demás el tiempo que sigue.

Publicaré el script a continuación. Pero primero, aquí están las instrucciones para una conversión …

Ejecuté el script en OS X 10.7.5 Lion. Python salió de la caja.

Para generar el archivo de entrada MySQL desde su base de datos SQLite3 existente, ejecute la secuencia de comandos en sus propios archivos de la siguiente manera:

 Snips$ sqlite3 original_database.sqlite3 .dump | python ~/scripts/dump_for_mysql.py > dumped_data.sql 

Luego copié el archivo dumped_sql.sql resultante en un cuadro de Linux que ejecutaba Ubuntu 10.04.4 LTS donde residía mi base de datos MySQL.

Otro problema que tuve al importar el archivo MySQL fue que algunos caracteres Unicode UTF-8 (específicamente comillas simples) no se estaban importando correctamente, así que tuve que agregar un interruptor al comando para especificar UTF-8.

El comando resultante para ingresar los datos en una nueva base de datos MySQL vacía es la siguiente:

 Snips$ mysql -p -u root -h 127.0.0.1 test_import --default-character-set=utf8 < dumped_data.sql 

Déjalo cocinar, ¡y debería ser! No olvide examinar sus datos, antes y después.

Entonces, como solicitó OP, es rápido y fácil, cuando sabes cómo hacerlo. 🙂

Por otro lado, una cosa de la que no estaba seguro antes de estudiar esta migración, era si se crearía y se actualizaría en los valores de campo; la buena noticia para mí es que sí lo están, así que podría migrar mis datos de producción existentes.

¡Buena suerte!

ACTUALIZAR

Desde que hice este cambio, noté un problema que no había notado antes. En mi aplicación Rails, mis campos de texto se definen como 'cadena', y esto se transfiere al esquema de la base de datos. El proceso descrito aquí da como resultado que estos se definan como VARCHAR (255) en la base de datos MySQL. Esto coloca un límite de 255 caracteres en estos tamaños de campo, y cualquier cosa más allá de esto se truncó silenciosamente durante la importación. Para admitir una longitud de texto superior a 255, el esquema de MySQL necesitaría usar 'TEXTO' en lugar de VARCHAR (255), creo. El proceso definido aquí no incluye esta conversión.


Aquí está el script de Python fusionado y revisado que funcionó para mis datos:

 #!/usr/bin/env python import re import fileinput def this_line_is_useless(line): useless_es = [ 'BEGIN TRANSACTION', 'COMMIT', 'sqlite_sequence', 'CREATE UNIQUE INDEX', 'PRAGMA foreign_keys=OFF' ] for useless in useless_es: if re.search(useless, line): return True def has_primary_key(line): return bool(re.search(r'PRIMARY KEY', line)) searching_for_end = False for line in fileinput.input(): if this_line_is_useless(line): continue # this line was necessary because ''); was getting # converted (inappropriately) to \'); if re.match(r".*, ''\);", line): line = re.sub(r"''\);", r'``);', line) if re.match(r'^CREATE TABLE.*', line): searching_for_end = True m = re.search('CREATE TABLE "?([A-Za-z_]*)"?(.*)', line) if m: name, sub = m.groups() line = "DROP TABLE IF EXISTS %(name)s;\nCREATE TABLE IF NOT EXISTS `%(name)s`%(sub)s\n" line = line % dict(name=name, sub=sub) line = line.replace('AUTOINCREMENT','AUTO_INCREMENT') line = line.replace('UNIQUE','') line = line.replace('"','') else: m = re.search('INSERT INTO "([A-Za-z_]*)"(.*)', line) if m: line = 'INSERT INTO %s%s\n' % m.groups() line = line.replace('"', r'\"') line = line.replace('"', "'") line = re.sub(r"(?< !')'t'(?=.)", r"1", line) line = re.sub(r"(? 

Recientemente tuve que migrar de MySQL a JavaDB para un proyecto en el que nuestro equipo está trabajando. Encontré una biblioteca Java escrita por Apache llamada DdlUtils que lo hizo bastante fácil. Proporciona una API que le permite hacer lo siguiente:

  1. Descubra el esquema de una base de datos y expórtela como un archivo XML.
  2. Modificar un DB basado en este esquema.
  3. Importe registros de una base de datos a otra, suponiendo que tengan el mismo esquema.

Las herramientas con las que terminamos no fueron completamente automáticas, pero funcionaron bastante bien. Incluso si su aplicación no está en Java, no debería ser demasiado difícil utilizar algunas herramientas pequeñas para realizar una migración única. Creo que pude sacar de nuestra migración con menos de 150 líneas de código.

Probablemente la forma más rápida y fácil sea utilizando el comando sqlite .dump, en este caso, cree un volcado de la base de datos de muestra.

 sqlite3 sample.db .dump > dump.sql 

A continuación, puede (en teoría) importar esto en la base de datos mysql, en este caso la base de datos de prueba en el servidor de base de datos 127.0.0.1, utilizando el usuario root.

 mysql -p -u root -h 127.0.0.1 test < dump.sql 

Digo en teoría, ya que hay algunas diferencias entre las gramáticas.

En sqlite las transacciones comienzan

 BEGIN TRANSACTION; ... COMMIT; 

MySQL usa solo

 BEGIN; ... COMMIT; 

Existen otros problemas similares (vuelven a la mente los verificadores y las comillas dobles) pero nada que encuentre ni reemplace no podría solucionarlo.

Quizás debería preguntar por qué está migrando, si el rendimiento / tamaño de la base de datos es el problema, tal vez revisar el esquema, si el sistema se está moviendo a un producto más potente, este podría ser el momento ideal para planificar el futuro de sus datos.

Obtenga un volcado de SQL

 moose@pc08$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql 

Volcado de importación a MySQL

Para pequeñas importaciones:

 moose@pc08$ mysql -u  -p Enter password: .... mysql> use somedb; Database changed mysql> source myTemporarySQLFile.sql; 

o

 mysql -u root -p somedb < myTemporarySQLFile.sql 

Esto le pedirá una contraseña. Tenga en cuenta: si desea ingresar su contraseña directamente, debe hacerlo SIN espacio, directamente después de -p :

 mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql 

Para volcados más grandes:

mysqlimport u otras herramientas de importación como BigDump .

BigDump te da una barra de progreso:

enter image description here

Si está usando Python / Django es bastante fácil:

crear dos bases de datos en settings.py (como https://docs.djangoproject.com/en/1.11/topics/db/multi-db/ )

entonces simplemente haz así:

 objlist = ModelObject.objects.using('sqlite').all() for obj in objlist: obj.save(using='mysql') 

MySQL Workbench (licencia GPL) migra desde SQLite muy fácilmente a través del asistente de Migración de Base de Datos . Se instala en Windows, Ubuntu, RHEL, Fedora y OS X.

La secuencia de comandos python funcionó después de algunas modificaciones de la siguiente manera:

 # Remove "PRAGMA foreign_keys=OFF; from beginning of script # Double quotes were not removed from INSERT INTO "BaselineInfo" table, check if removed from subsequent tables. Regex needed AZ added. # Removed backticks from CREATE TABLE # Added replace AUTOINCREMENT with AUTO_INCREMENT # Removed replacement, #line = line.replace('"', '`').replace("'", '`') 

 useless_es = [ 'BEGIN TRANSACTION', 'COMMIT', 'sqlite_sequence', 'CREATE UNIQUE INDEX', 'PRAGMA foreign_keys=OFF', ] 

 m = re.search('CREATE TABLE "?([A-Za-z_]*)"?(.*)', line) if m: name, sub = m.groups() line = "DROP TABLE IF EXISTS %(name)s;\nCREATE TABLE IF NOT EXISTS %(name)s%(sub)s\n" line = line % dict(name=name, sub=sub) line = line.replace('AUTOINCREMENT','AUTO_INCREMENT') line = line.replace('UNIQUE','') line = line.replace('"','') else: m = re.search('INSERT INTO "([A-Za-z_]*)"(.*)', line) if m: line = 'INSERT INTO %s%s\n' % m.groups() line = line.replace('"', r'\"') line = line.replace('"', "'") 

Utilizo el cargador de datos para migrar casi cualquier dato, me ayuda a convertir MSSQL a MYSQL, acceso MS a MSSQL, mysql, cargador csv, foxpro y acceso MSSQL a MS, MYSQl, CSV, foxpro, etc. En mi opinión, este es el mejor Herramienta de migración de datos

Descargue gratis: http://www.dbload.com

Basado en la solución de Jims: ¿forma rápida y fácil de migrar SQLite3 a MySQL?

 sqlite3 your_sql3_database.db .dump | python ./dump.py > your_dump_name.sql cat your_dump_name.sql | sed '1d' | mysql --user=your_mysql_user --default-character-set=utf8 your_mysql_db -p 

Esto funciona para mí Utilizo sed solo para arrojar la primera línea, que no es similar a mysql, pero también podría modificar el script dump.py para descartar esta línea.

Ha … ¡Desearía haber encontrado esto primero! Mi respuesta fue a este post … secuencia de comandos para convertir mysql dump archivo sql en formato que se puede importar a sqlite3 db

La combinación de los dos sería exactamente lo que necesitaba:


Cuando la base de datos sqlite3 se va a usar con ruby, es posible que desee cambiar:

 tinyint([0-9]*) 

a:

 sed 's/ tinyint(1*) / boolean/g ' | sed 's/ tinyint([0|2-9]*) / integer /g' | 

por desgracia, esto solo funciona a medias porque a pesar de que está insertando 1 y 0 en un campo marcado como booleano, sqlite3 los almacena como 1 y 0, por lo que debe pasar y hacer algo como:

 Table.find(:all, :conditions => {:column => 1 }).each { |t| t.column = true }.each(&:save) Table.find(:all, :conditions => {:column => 0 }).each { |t| t.column = false}.each(&:save) 

pero fue útil tener el archivo sql para buscar todos los booleanos.

Fallino identificó correctamente la ubicación del error en el script. Tengo la solución. El problema son las siguientes líneas:

 line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line) line = line.replace('THIS_IS_TRUE', '1') line = re.sub(r"([^'])'f'(.)", "\1THIS_IS_FALSE\2", line) line = line.replace('THIS_IS_FALSE', '0') 

El patrón de reemplazo (segundo parámetro) en las llamadas re.sub es una cadena “regular”, por lo que en lugar de \ 1 expandirse a la primera coincidencia de expresiones regulares, se expande a un valor literal 0x01. Del mismo modo, \ 2 se expande a 0x02. Por ejemplo, una línea que contiene:, ‘t’, ‘f’, sería reemplazada por: <0x01> 10 <0x02>
(La primera sustitución cambia, ‘t’, a <0x1> 1 <0x2> La segunda sustitución cambia <0x02> ‘f’, a <0x1> 0 <0x1>)

La solución es cambiar las cadenas de reemplazo agregando un prefijo ‘r’ o escapando el \ 1 y \ 2 en la cadena existente. Dado que la manipulación fácil de las cadenas de expresiones regulares es para lo que son las cadenas sin formato, esta es la solución que las usa:

 line = re.sub(r"([^'])'t'(.)", r"\1THIS_IS_TRUE\2", line) line = line.replace('THIS_IS_TRUE', '1') line = re.sub(r"([^'])'f'(.)", r"\1THIS_IS_FALSE\2", line) line = line.replace('THIS_IS_FALSE', '0') 

este software listo para usar: funciona para mí. pruébalo y deja que otros lo sepan.

https://dbconvert.com/sqlite/mysql/

En adición:

Tuve que hacer un pequeño cambio: de alguna manera, el autoincremento de un campo (un campo encontrado a partir del mensaje de error) no estaba habilitado. Entonces en phpmyadmin verifico la propiedad A_I de este campo y funciona completamente. Espero eso ayude.

Dunn.

No hay necesidad de ningún script, comando, etc.

solo debe exportar su base de datos sqlite como un archivo .csv y luego importarla en Mysql usando phpmyadmin.

Lo usé y funcionó increíble …

Este script está bien, excepto en este caso que, por supuesto, me he encontrado:

 INSERTAR EN "requestcomparison_stopword" VALUES (149, 'f');
 INSERTAR EN "requestcomparison_stopword" VALUES (420, 't');

El script debería dar esta salida:

 INSERT INTO requestcomparison_stopword VALUES (149, 'f');
 INSERT INTO requestcomparison_stopword VALUES (420, 't');

Pero da lugar a ese resultado:

 INSERT INTO requestcomparison_stopword VALUES (1490;
 INSERT INTO requestcomparison_stopword VALUES (4201;

con algunos extraños personajes no ascii alrededor del último 0 y 1.

Esto no apareció más cuando comenté las siguientes líneas del código (43-46) pero aparecieron otros problemas:

 line = re.sub(r"([^'])'t'(.)", "\1THIS_IS_TRUE\2", line) line = line.replace('THIS_IS_TRUE', '1') line = re.sub(r"([^'])'f'(.)", "\1THIS_IS_FALSE\2", line) line = line.replace('THIS_IS_FALSE', '0') 

Este es solo un caso especial, cuando queremos agregar un valor que sea ‘f’ o ‘t’ pero no estoy realmente cómodo con las expresiones regulares, solo quería ver que alguien corrige este caso.

De todos modos, ¡muchas gracias por ese guion tan útil!

Esta solución simple funcionó para mí:

 < ?php $sq = new SQLite3( 'sqlite3.db' ); $tables = $sq->query( 'SELECT name FROM sqlite_master WHERE type="table"' ); while ( $table = $tables->fetchArray() ) { $table = current( $table ); $result = $sq->query( sprintf( 'SELECT * FROM %s', $table ) ); if ( strpos( $table, 'sqlite' ) !== false ) continue; printf( "-- %s\n", $table ); while ( $row = $result->fetchArray( SQLITE3_ASSOC ) ) { $values = array_map( function( $value ) { return sprintf( "'%s'", mysql_real_escape_string( $value ) ); }, array_values( $row ) ); printf( "INSERT INTO `%s` VALUES( %s );\n", $table, implode( ', ', $values ) ); } } 

Tomé el script de Python desde https://stackoverflow.com/a/32243979/746459 (arriba) y lo arreglé para hacer frente a nuestros propios esquemas sqlite. Hubo algunos problemas para tratar.

Puede encontrarlo en control de fuente aquí: https://bitbucket.org/mjogltd/sqlite3mysql

También está disponible lo mismo que una imagen Docker, aquí: https://hub.docker.com/r/mjog/sqlite3mysql/ – es totalmente utilizable incluso bajo un escritorio de Windows.

Escribí este script simple en Python3. Se puede usar como clase incluida o secuencia de comandos independiente invocada a través de un shell de terminal. De forma predeterminada, importa todos los enteros como int(11) y cadenas como varchar(300) , pero todo eso se puede ajustar en el constructor o en los argumentos del script, respectivamente.

NOTA: Requiere MySQL Connector / Python 2.0.4 o superior

Aquí hay un enlace a la fuente en GitHub si le resulta difícil leer el siguiente código: https://github.com/techouse/sqlite3-to-mysql/blob/master/sqlite3mysql.py

 #!/usr/bin/env python3 __author__ = "Klemen Tušar" __email__ = "techouse@gmail.com" __copyright__ = "GPL" __version__ = "1.0.1" __date__ = "2015-09-12" __status__ = "Production" import os.path, sqlite3, mysql.connector from mysql.connector import errorcode class SQLite3toMySQL: """ Use this class to transfer an SQLite 3 database to MySQL. NOTE: Requires MySQL Connector/Python 2.0.4 or higher (https://dev.mysql.com/downloads/connector/python/) """ def __init__(self, **kwargs): self._properties = kwargs self._sqlite_file = self._properties.get('sqlite_file', None) if not os.path.isfile(self._sqlite_file): print('SQLite file does not exist!') exit(1) self._mysql_user = self._properties.get('mysql_user', None) if self._mysql_user is None: print('Please provide a MySQL user!') exit(1) self._mysql_password = self._properties.get('mysql_password', None) if self._mysql_password is None: print('Please provide a MySQL password') exit(1) self._mysql_database = self._properties.get('mysql_database', 'transfer') self._mysql_host = self._properties.get('mysql_host', 'localhost') self._mysql_integer_type = self._properties.get('mysql_integer_type', 'int(11)') self._mysql_string_type = self._properties.get('mysql_string_type', 'varchar(300)') self._sqlite = sqlite3.connect(self._sqlite_file) self._sqlite.row_factory = sqlite3.Row self._sqlite_cur = self._sqlite.cursor() self._mysql = mysql.connector.connect( user=self._mysql_user, password=self._mysql_password, host=self._mysql_host ) self._mysql_cur = self._mysql.cursor(prepared=True) try: self._mysql.database = self._mysql_database except mysql.connector.Error as err: if err.errno == errorcode.ER_BAD_DB_ERROR: self._create_database() else: print(err) exit(1) def _create_database(self): try: self._mysql_cur.execute("CREATE DATABASE IF NOT EXISTS `{}` DEFAULT CHARACTER SET 'utf8'".format(self._mysql_database)) self._mysql_cur.close() self._mysql.commit() self._mysql.database = self._mysql_database self._mysql_cur = self._mysql.cursor(prepared=True) except mysql.connector.Error as err: print('_create_database failed creating databse {}: {}'.format(self._mysql_database, err)) exit(1) def _create_table(self, table_name): primary_key = '' sql = 'CREATE TABLE IF NOT EXISTS `{}` ( '.format(table_name) self._sqlite_cur.execute('PRAGMA table_info("{}")'.format(table_name)) for row in self._sqlite_cur.fetchall(): column = dict(row) sql += ' `{name}` {type} {notnull} {auto_increment}, '.format( name=column['name'], type=self._mysql_string_type if column['type'].upper() == 'TEXT' else self._mysql_integer_type, notnull='NOT NULL' if column['notnull'] else 'NULL', auto_increment='AUTO_INCREMENT' if column['pk'] else '' ) if column['pk']: primary_key = column['name'] sql += ' PRIMARY KEY (`{}`) ) ENGINE = InnoDB CHARACTER SET utf8'.format(primary_key) try: self._mysql_cur.execute(sql) self._mysql.commit() except mysql.connector.Error as err: print('_create_table failed creating table {}: {}'.format(table_name, err)) exit(1) def transfer(self): self._sqlite_cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") for row in self._sqlite_cur.fetchall(): table = dict(row) # create the table self._create_table(table['name']) # populate it print('Transferring table {}'.format(table['name'])) self._sqlite_cur.execute('SELECT * FROM "{}"'.format(table['name'])) columns = [column[0] for column in self._sqlite_cur.description] try: self._mysql_cur.executemany("INSERT IGNORE INTO `{table}` ({fields}) VALUES ({placeholders})".format( table=table['name'], fields=('`{}`, ' * len(columns)).rstrip(' ,').format(*columns), placeholders=('%s, ' * len(columns)).rstrip(' ,') ), (tuple(data) for data in self._sqlite_cur.fetchall())) self._mysql.commit() except mysql.connector.Error as err: print('_insert_table_data failed inserting data into table {}: {}'.format(table['name'], err)) exit(1) print('Done!') def main(): """ For use in standalone terminal form """ import sys, argparse parser = argparse.ArgumentParser() parser.add_argument('--sqlite-file', dest='sqlite_file', default=None, help='SQLite3 db file') parser.add_argument('--mysql-user', dest='mysql_user', default=None, help='MySQL user') parser.add_argument('--mysql-password', dest='mysql_password', default=None, help='MySQL password') parser.add_argument('--mysql-database', dest='mysql_database', default=None, help='MySQL host') parser.add_argument('--mysql-host', dest='mysql_host', default='localhost', help='MySQL host') parser.add_argument('--mysql-integer-type', dest='mysql_integer_type', default='int(11)', help='MySQL default integer field type') parser.add_argument('--mysql-string-type', dest='mysql_string_type', default='varchar(300)', help='MySQL default string field type') args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() exit(1) converter = SQLite3toMySQL( sqlite_file=args.sqlite_file, mysql_user=args.mysql_user, mysql_password=args.mysql_password, mysql_database=args.mysql_database, mysql_host=args.mysql_host, mysql_integer_type=args.mysql_integer_type, mysql_string_type=args.mysql_string_type ) converter.transfer() if __name__ == '__main__': main() 

He revisado cuidadosamente todas las respuestas en esta publicación, así como las respuestas en otra publicación relacionada Traduciendo Perl a Python . Sin embargo, ninguno podría resolver completamente mi problema.

Mi caso es que necesito migrar una base de datos de Trac de sqlite a MySQL, y la base de datos contiene mucho contenido de wiki basado en tecnología. Por lo tanto, dentro de los valores INSERT INTO , podría haber sentencias SQL como CREATE TABLE y AUTOINCREMENT . Pero el reemplazo línea por línea podría tener reemplazos incorrectos allí.

Finalmente, he escrito mi propia herramienta para este propósito:

https://github.com/motherapp/sqlite_sql_parser

El uso es relativamente simple:

python parse_sqlite_sql.py export.sql

Se generarán dos archivos: export.sql.schema.sql y export.sql.data.sql . Uno para el esquema de BD actualizado, y el otro para los datos de base de datos actualizados.

Se podrían hacer más modificaciones manuales en el archivo de esquema DB utilizando cualquier editor de texto, sin preocuparse por cambiar el contenido.

Espero que pueda ayudar a otros en el futuro.

 echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql 

cuidado con las declaraciones CREATE