studio - ¿Una forma rápida y fácil de migrar SQLite3 a MySQL?
sqlite website (26)
¿Alguien sabe una manera rápida y fácil de migrar una base de datos SQLite3 a MySQL?
Obtener un volcado de SQL
moose@pc08$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql
Importar volcado a MySQL
Para pequeñas importaciones:
moose@pc08$ mysql -u <username> -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 vertederos más grandes:
mysqlimport u otras herramientas de importación como BigDump .
BigDump te da una barra de progreso:
Acabo de pasar por este proceso y hay mucha ayuda e información muy buenas en esta Q / A, pero descubrí que tenía que reunir varios elementos (más algunos de otros Q / As) para obtener una solución funcional Para migrar con éxito.
Sin embargo, incluso después de combinar las respuestas existentes, descubrí que la secuencia de comandos de Python no funcionaba completamente para mí, ya que no funcionaba donde había varias ocurrencias booleanas en un INSERT. Vea here por qué ese fue el caso.
Entonces, pensé que publicaría 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 otros el tiempo que sigue.
Voy a publicar el guión 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 trabajó fuera de la caja.
Para generar el archivo de entrada MySQL desde su base de datos SQLite3 existente, ejecute el script 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 a una caja de Linux que ejecuta Ubuntu 10.04.4 LTS donde residiría mi base de datos MySQL.
Otro problema que tuve al importar el archivo MySQL fue que algunos caracteres UTF-8 Unicode (específicamente, comillas simples) no se importaban correctamente, por lo 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 el siguiente:
Snips$ mysql -p -u root -h 127.0.0.1 test_import --default-character-set=utf8 < dumped_data.sql
Deja que se cocine, y eso debería ser! No olvides analizar tus datos, antes y después.
Entonces, como lo solicitó el OP, es rápido y fácil, ¡cuando sabes cómo! :-)
Aparte de eso, una cosa de la que no estaba seguro antes de analizar esta migración era si los valores de campo created_at y updated_at se mantendrían; la buena noticia para mí es que sí lo están, por lo que podría migrar mis datos de producción existentes.
¡Buena suerte!
ACTUALIZAR
Desde que hice este cambio, he notado un problema que no había notado antes. En mi aplicación Rails, mis campos de texto se definen como ''cadena'', y esto se aplica al esquema de la base de datos. El proceso descrito aquí hace 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 MySQL tendría que usar ''TEXTO'' en lugar de VARCHAR (255), creo. El proceso definido aquí no incluye esta conversión.
Aquí está el script de Python combinado 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"(?<!'')''f''(?=.)", r"0", line)
# Add auto_increment if it''s 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
# 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)
print line,
Aquí hay una lista de convertidores (no actualizada desde 2011):
Un método alternativo que funcionaría bien pero que rara vez se menciona es: use una clase de ORM que resuma las diferencias específicas de la base de datos para usted. por ejemplo, los obtiene en PHP ( RedBean ), Python (capa ORM de Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )es decir, podría hacer esto:
- Cargar datos de la base de datos de origen utilizando la clase ORM.
- Almacena datos en memoria o serializa en disco.
- Almacene los datos en la base de datos de destino utilizando la clase ORM.
Aquí hay una secuencia de comandos de python, creada a partir de la respuesta de Shalmanese y algo de ayuda de Alex martelli en Translating Perl to Python
Lo estoy haciendo wiki de la comunidad, así que por favor siéntase libre de editar y refactorizar, siempre y cuando no rompa la funcionalidad (afortunadamente solo podemos revertir) - Es bastante feo pero funciona
use like so (asumiendo que el script se llama dump_for_mysql.py
:
sqlite3 sample.db .dump | python dump_for_mysql.py > dump.sql
Que luego se puede importar en mysql
nota: debe agregar restricciones de clave externa manualmente ya que sqlite no las admite realmente
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,
Basado en la solución de Jims: ¿Una 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 mi Utilizo sed solo para lanzar la primera línea, que no es similar a mysql, pero también puede modificar el script dump.py para eliminar esta línea.
El script de 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 A-Z 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(''"'', "''")
...
Es complicado porque los archivos de volcado son específicos del proveedor de la base de datos.
Si estás usando Rails, existe un gran complemento para esto. Lea: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/
Actualizar
Tenedor actualmente mantenido: https://github.com/ludicast/yaml_db
Escribí este sencillo script en Python3. Se puede usar como una clase incluida o un script independiente invocado a través de un terminal shell. De forma predeterminada, importa todos los enteros como int(11)
y las cadenas como varchar(300)
, pero todo eso se puede ajustar en los argumentos del constructor o script, respectivamente.
NOTA: Requiere MySQL Connector / Python 2.0.4 o superior
Aquí hay un enlace a la fuente en GitHub si encuentra el código a continuación difícil de leer: https://github.com/techouse/sqlite3-to-mysql/blob/master/sqlite3mysql.py
#!/usr/bin/env python3
__author__ = "Klemen Tušar"
__email__ = "[email protected]"
__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()
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 ) );
}
}
Este script está bien, excepto en este caso que, por supuesto, he conocido:
INSERT INTO "requestcomparison_stopword" VALUES(149,''f''); INSERT INTO "requestcomparison_stopword" VALUES(420,''t'');
El script debe dar esta salida:
INSERT INTO requestcomparison_stopword VALUES(149,''f''); INSERT INTO requestcomparison_stopword VALUES(420,''t'');
Pero da en cambio esa salida:
INSERT INTO requestcomparison_stopword VALUES(1490; INSERT INTO requestcomparison_stopword VALUES(4201;
con algunos caracteres extraños no ascii alrededor del último 0 y 1.
Esto ya no apareció 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 detectar este caso para que lo corrija alguien.
De todos modos muchas gracias por ese práctico guión !!!
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 0x01 literal. Asimismo, / 2 se expande a 0x02. Por ejemplo, una línea que contenga:, ''t'', ''f'', se reemplazará con: <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 de / 1 y / 2 en la cadena existente. Ya que la manipulación fácil de las cadenas de expresiones regulares es para lo que son las cadenas en bruto, aquí está la solución al usarlas:
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'')
Ha ... ¡Ojalá hubiera encontrado esto primero! Mi respuesta fue a este post ... script para convertir mysql dump sql file en formato que puede ser importado a sqlite3 db
Combinar los dos sería exactamente lo que necesitaba:
Cuando la base de datos sqlite3 se utilizará 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'' |
lamentablemente, esta mitad solo funciona 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 tiene que 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 y encontrar todos los booleanos.
Hace poco tuve que migrar de MySQL a JavaDB para un proyecto en el que nuestro equipo está trabajando. Encontré una biblioteca de Java escrita por Apache llamada DdlUtils que hizo esto bastante fácil. Proporciona una API que te permite hacer lo siguiente:
- Descubra el esquema de una base de datos y expórtelo como un archivo XML.
- Modificar un DB basado en este esquema.
- Importe registros de un DB a otro, asumiendo que tienen el mismo esquema.
Las herramientas con las que terminamos no estaban completamente automatizadas, pero funcionaron bastante bien. Incluso si su aplicación no está en Java, no debería ser demasiado difícil armar 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.
He comprobado cuidadosamente todas las respuestas en esta publicación, así como las respuestas en otra publicación relacionada, Traduciendo Perl a Python . Sin embargo, ninguno pudo resolver completamente mi problema.
Mi escenario es que necesito migrar una base de datos de Trac de sqlite a MySQL, y la base de datos contiene una gran cantidad de contenido wiki basado en tecnología. Por lo tanto, dentro de los valores de INSERT INTO
, podría haber sentencias de SQL como CREATE TABLE
y AUTOINCREMENT
. Pero el reemplazo línea por línea podría tener reemplazos erróneos 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ían dos archivos: export.sql.schema.sql
y export.sql.data.sql
. Uno para el esquema de base de datos actualizado y el otro para datos de base de datos actualizados
Uno podría hacer más modificaciones manuales en el archivo de esquema de base de datos utilizando cualquier editor de texto, sin preocuparse por cambiar el contenido.
Espero que pueda ayudar a otros en el futuro.
MySQL Workbench (licencia GPL) migra fácilmente desde SQLite a través del asistente de migración de base de datos . Se instala en Windows, Ubuntu, RHEL, Fedora y OS X.
No hay necesidad de ningún script, comando, etc ...
solo tiene que exportar su base de datos sqlite como un archivo .csv
y luego importarlo a Mysql usando phpmyadmin.
Lo usé y funcionó increíble ...
Normalmente uso la función Exportar / importar tablas de IntelliJ DataGrip .
Puedes ver el progreso en la esquina inferior derecha.
El ]
Parece que todo el mundo comienza con algunas expresiones de greps y perl y de alguna manera obtienes algo que funciona para tu conjunto de datos en particular, pero no tienes idea si se importaron los datos correctamente o no. Estoy realmente 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 sintaxis SQL que conozco entre los dos formatos de archivo: Las líneas que comienzan con:
- COMENZAR LA TRANSACCION
- COMETER
- sqlite_sequence
- CREAR ÍNDICE ÚNICO
no se utilizan 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 usa comillas simples para cadenas dentro de las cláusulas INSERT INTO
- SQLlite y MySQL tienen diferentes maneras de escapar de cadenas dentro de las cláusulas INSERT INTO
- SQLlite usa ''t'' y ''f'' para los booleanos, MySQL usa 1 y 0 (una expresión regular simple para esto puede fallar cuando tienes una cadena como: ''Sí, no'' dentro de tu INSERT INTO)
- SQLLite usa AUTOINCREMENT, MySQL usa AUTO_INCREMENT
Aquí hay un script de Perl pirateado muy básico que funciona para mi conjunto de datos y comprueba muchas más de estas condiciones que otros scripts de Perl que encontré en la web. Nu garantiza que funcionará para sus datos, pero puede modificarlo y publicarlo 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;
}
}
Probablemente, la forma más fácil y rápida es usar el comando sqlite .dump, en este caso, crear un volcado de la base de datos de muestra.
sqlite3 sample.db .dump > dump.sql
Luego 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, usando la raíz del usuario.
mysql -p -u root -h 127.0.0.1 test < dump.sql
Lo digo en teoría ya que hay algunas diferencias entre las gramáticas.
En sqlite comienzan las transacciones.
BEGIN TRANSACTION;
...
COMMIT;
MySQL usa solo
BEGIN;
...
COMMIT;
Hay otros problemas similares (los varchars y las comillas dobles vuelven a la mente), pero nada que encontrar y reemplazar no se pudo solucionar.
Tal vez debería preguntar por qué está migrando, si el problema es el rendimiento / tamaño de la base de datos, tal vez tenga que volver a reiniciar el esquema, si el sistema se está moviendo hacia un producto más poderoso, este podría ser el momento ideal para planificar el futuro de sus datos.
Si estás usando Python / Django es bastante fácil:
cree dos bases de datos en settings.py (como aquí https://docs.djangoproject.com/en/1.11/topics/db/multi-db/ )
entonces hazlo así:
objlist = ModelObject.objects.using(''sqlite'').all()
for obj in objlist:
obj.save(using=''mysql'')
Sorprendido, nadie lo ha mencionado hasta ahora, pero en realidad hay una herramienta explícita para esto. Está en perl, SQL: Traductor: http://sqlfairy.sourceforge.net/
Convierte entre la mayoría de las formas de datos tabulares (diferentes formatos de SQL, hoja de cálculo de Excel) e incluso crea diagramas de su esquema de SQL.
Tomé el script de Python de https://.com/a/32243979/746459 (arriba) y lo arreglé para hacer frente a nuestros propios esquemas de sqlite. Hubo algunos problemas con los que lidiar.
Puede encontrarlo en el control de código fuente aquí: https://bitbucket.org/mjogltd/sqlite3mysql
También está disponible la misma cosa envuelta como una imagen de Docker, aquí: https://hub.docker.com/r/mjog/sqlite3mysql/ : es completamente utilizable incluso en un escritorio de Windows.
Utilizo el cargador de datos para migrar casi cualquier dato, me ayuda a convertir MSSQL a MYSQL, MS Access a MSSQL, mysql, csv loader, foxpro y MSSQL a MS access, MYSQl, CSV, foxpro, etc. Desde mi punto de vista, este es el mejor. Herramienta de migración de datos
Descarga gratuita: http://www.dbload.com
este software de la caja - funciona para mí. Pruébalo y deja que otros sepan.
https://dbconvert.com/sqlite/mysql/
Adicionalmente:
Tuve que hacer un pequeño cambio: de alguna manera el auto_increment de un campo (un campo encontrado en el mensaje de error) no estaba habilitado. Así que en phpmyadmin compruebo la propiedad A_I de este campo y funciona completamente. Espero eso ayude.
Dunn
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql
Cuidado con las declaraciones CREATE
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