¿Forma rápida y fácil de migrar SQLite3 a MySQL? [cerrado]

Respuestas:

62

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 ORM que abstraiga las diferencias específicas de la base de datos para usted. por ejemplo, los obtienes en PHP ( RedBean ), Python (capa ORM de Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )

es decir, podrías hacer esto:

  1. Cargue datos de la base de datos de origen utilizando la clase ORM.
  2. Almacene datos en la memoria o serialice en el disco.
  3. Almacene datos en la base de datos de destino utilizando la clase ORM.
David d C e Freitas
fuente
107

Todo el mundo parece comenzar con unos pocos greps y expresiones 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. Me sorprende mucho que nadie haya construido una biblioteca sólida que pueda convertir entre los dos.

Aquí una lista de TODAS las diferencias en sintaxis 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

  • Usos de SQLlite CREATE TABLE/INSERT INTO "table_name"y usos de MySQLCREATE 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 INSERT INTOcláusulas
  • SQLlite y MySQL tienen diferentes formas de escapar de cadenas dentro de INSERT INTOcláusulas
  • SQLlite usa 't'y 'f'para booleanos, MySQL usa 1y 0(una expresión regular simple para esto puede fallar cuando tiene una cadena como: 'Sí, no' dentro de su INSERT INTO)
  • Usos de SQLLite AUTOINCREMENT, usos de MySQLAUTO_INCREMENT

Aquí hay un script perl pirateado muy básico que funciona para mi conjunto de datos y comprueba muchas más de estas condiciones que otros scripts perl que encontré en la web. Nu garantiza que funcionará para sus datos, pero puede modificarlos y publicarlos 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_]*)\"(.*)/i){
            $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_]*)\"(.*)/i){
            $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;
    }
}
Shalmanese
fuente
8
Alex martelli hizo un gran trabajo reescribiendo esto como python en stackoverflow.com/questions/1067060/perl-to-python
Jiaaro el
Agregué la secuencia de comandos completa de Python (la secuencia de comandos Perl por sí sola no funcionó para mí ... necesitaba un procesamiento adicional para manejar claves e índices extranjeros)
Jiaaro
Reescribí esta respuesta en la otra pregunta stackoverflow.com/questions/1067060/_/1070463#1070463
Brad Gilbert
2
COMMIT y CREATE UNIQUE INDEX son comandos válidos de MySQL, corríjalo.
niutech
55
Entiendo que su secuencia de comandos es "rápida y sucia", pero también muy útil, así que aquí hay algunas adiciones / correcciones de errores: * después de && ($line !~ /CREATE UNIQUE INDEX/)agregar && ($line !~ /PRAGMA foreign_keys=OFF/) * la expresión regular de coincidencia de nombre de tabla pierde dígitos, es decir, en lugar de $line =~ /INSERT INTO \"([a-z_]*)\"(.*)/debe haber $line =~ /INSERT INTO \"([a-z_1-9]*)\"(.*)/ Espero que esto ayude al futuro lectores
Michał Leon
50

Aquí hay un script de Python, construido a partir de la respuesta de Shalmanese y un poco de ayuda de Alex martelli en Translating Perl to Python

Lo estoy haciendo wiki comunitario, así que siéntase libre de editar y refactorizar siempre que no rompa la funcionalidad (afortunadamente podemos retroceder): es bastante feo pero funciona

use así (suponiendo que el script se llame dump_for_mysql.py:

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

Que luego puedes importar a mysql

nota: debe 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,
Jiaaro
fuente
2
Hola Jim, en mi conjunto de datos, cada primera instrucción INSERT está envuelta por una comilla inversa en lugar de una comilla simple: __ DROP TABLE IF EXISTS schema_migrations; CREAR TABLA SI NO EXISTE schema_migrations( versionvarchar (255) NO NULO); INSERTAR EN Schema_migrations VALUES ( 20100714032840); INSERTAR EN VALORES de schema_migrations ('20100714033251'); __
David
bueno ... no aparece arriba, pero las comillas aparecen dentro de los VALORES ([AQUÍ] 20100714032840 [/ AQUÍ])
David
1
El AUTOINCREMENTO en Mysql es AUTO_INCREMENT. El guión no tiene en cuenta eso.
giuseppe
Esto no funciona para una base de datos wiki de medios. Muchos errores: Blobvartipo de datos, ticks de retroceso en la declaración CREATE ...
Frank Hintsch
1
no funciona Puede que no se tengan en cuenta todas las condiciones ...
Himanshu Bansal
10

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 a 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 la raíz del usuario.

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 comienzan las transacciones

BEGIN TRANSACTION;
...
COMMIT;

MySQL usa solo

BEGIN;
...
COMMIT;

Hay otros problemas similares (los varchars y las comillas dobles vuelven a mi mente) pero nada de encontrar y reemplazar no se pudo solucionar.

Tal vez debería preguntar por qué está migrando, si el problema es el tamaño del rendimiento / base de datos, quizás considere volver a iniciar 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.

Richard Gourlay
fuente
2
pero la tarea más difícil es la diferencia entre las gramáticas semanales
francois
8
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
Dashamir Hoxha
fuente
7

Acabo de pasar por este proceso, y hay mucha muy buena ayuda e información en este Q / A, pero descubrí que tenía que reunir varios elementos (más algunos de otros Q / A) para obtener una solución de trabajo en Para migrar con éxito.

Sin embargo, incluso después de combinar las respuestas existentes, descubrí que el script 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é ese fue el caso.

Entonces, pensé en publicar mi respuesta combinada 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.

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 salió de la caja.

Para generar el archivo de entrada MySQL de 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 en una caja de Linux que ejecuta 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 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

¡Déjalo cocinar, y eso debería ser! No olvides examinar tus datos antes y después.

Entonces, como lo solicitó el OP, ¡es rápido y fácil, cuando sabes cómo! :-)

Por otro lado, una cosa de la que no estaba seguro antes de analizar esta migración era si se preservarían los valores de campo created_at y updated_at; la buena noticia para mí es que sí lo son, por lo 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 traslada 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. Creo que para admitir una longitud de texto superior a 255, el esquema MySQL necesitaría usar 'TEXTO' en lugar de VARCHAR (255). El proceso definido aquí no incluye esta conversión.


Aquí está el script 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"(?<!')'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,
Recortes
fuente
1
Gracias. El script tal como está escrito anteriormente tiene un error de sintaxis; el "else:" en la línea 41 no está en el nivel de sangría adecuado. No me queda claro si las líneas de arriba deben estar sangradas o si está sucediendo algo más. ¿Quieres actualizar?
Dan Tenenbaum
5

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órtelo como un archivo XML.
  2. Modificar una base de datos basada 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 estaban completamente automatizadas, pero funcionaron bastante bien. Incluso si su aplicación no está en Java, no debería ser demasiado difícil preparar algunas herramientas pequeñas para realizar una migración única. Creo que pude extraer nuestra migración con menos de 150 líneas de código.

Programador ilegal
fuente
4

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

solo tiene que exportar su base de datos sqlite como un .csvarchivo y luego importarlo en Mysql usando phpmyadmin.

Lo usé y funcionó increíble ...

NavidIvaniano
fuente
En combinación con esto , esta es la única respuesta que funcionó para mí.
cdauth
3

Basado en la solución de Jims: ¿Una forma fácil y rápida 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 podría modificar el script dump.py para tirar esta línea.

alekwisnia
fuente
1
Tuve algunos problemas de codificación UTF-8 con los datos importados, pero agregar --default-character-set = utf8 al comando de importación parece haber solucionado eso. Tomado de este Q / A: stackoverflow.com/questions/346092/…
Snips
Ok, he agregado esto, ¿está bien?
alekwisnia
Ahí es donde estoy usando el interruptor adicional, sí.
Snips
3

Obtenga 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:

ingrese la descripción de la imagen aquí

Martin Thoma
fuente
12
Esto no funciona debido a ligeras diferencias de sintaxis y marcas en sqlite vs mysql. Aún necesita convertirlo manualmente.
dlite922
1

Ja ... Ojalá hubiera encontrado esto primero! Mi respuesta fue a esta publicación ... script para convertir mysql dump sql file en formato que se pueda importar a sqlite3 db

Combinar los dos sería exactamente lo que necesitaba:


Cuando la base de datos sqlite3 se vaya 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 la mitad porque aunque inserte 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.

daicoden
fuente
1

Escribí este simple script en Python3. Se puede usar como una clase incluida o un script independiente invocado a través de un shell de terminal. Por defecto, 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 encuentra el siguiente código difícil de leer: https://github.com/techouse/sqlite3-to-mysql

#!/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()
Klemen Tušar
fuente
0

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

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

El script debería dar este resultado:

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

Pero da en cambio esa salida:

INSERTAR EN requestcomparison_stopword VALUES (1490;
INSERTAR EN requestcomparison_stopword VALUES (4201;

con algunos extraños caracteres no ascii alrededor de los últimos 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 alguien lo corrija.

De todos modos muchas gracias por ese útil guión !!!


fuente
0

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 ) );
    }
}
soulseekah
fuente
-5
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql

cuidado con las declaraciones CREATE

mgribov
fuente