Domanda

Qualcuno conosce un modo semplice e veloce per migrare un database SQLite3 su MySQL?

È stato utile?

Soluzione

Ecco un elenco dei convertitori (non aggiornato dal 2011):


Un metodo alternativo che funzionerebbe bene ma che viene raramente menzionato è:usa una classe ORM che astrae le differenze specifiche del database per te.per esempio.li ottieni in PHP (Fagiolo rosso), Python (livello ORM di Django, Tempesta, SqlAlchemy), Rubino sui binari (Registrazione attiva), Cacao (CoreData)

cioè.potresti fare questo:

  1. Carica i dati dal database di origine utilizzando la classe ORM.
  2. Archiviare i dati in memoria o serializzarli su disco.
  3. Archiviare i dati nel database di destinazione utilizzando la classe ORM.

Altri suggerimenti

Sembra che tutti inizino con alcune espressioni greps e perl e in un certo senso ottieni qualcosa che funziona per il tuo particolare set di dati ma non hai idea se i dati sono stati importati correttamente o meno.Sono seriamente sorpreso che nessuno abbia creato una solida libreria in grado di convertire tra i due.

Ecco un elenco di TUTTE le differenze nella sintassi SQL che conosco tra i due formati di file:Le righe che iniziano con:

  • INIZIA LA TRANSAZIONE
  • COMMETTERE
  • sqlite_sequenza
  • CREA INDICE UNICO

non sono utilizzati in MySQL

  • Utilizza SQLlite CREATE TABLE/INSERT INTO "table_name" e MySQL utilizza CREATE TABLE/INSERT INTO table_name
  • MySQL non utilizza virgolette all'interno della definizione dello schema
  • MySQL utilizza virgolette singole per le stringhe all'interno del file INSERT INTO clausole
  • SQLlite e MySQL hanno modi diversi di eseguire l'escape delle stringhe all'interno INSERT INTO clausole
  • Utilizza SQLlite 't' E 'f' per i booleani, MySQL utilizza 1 E 0 (una semplice espressione regolare per questo può fallire quando hai una stringa come:"Io sì, tu no" dentro il tuo INSERT INTO)
  • SQLLite utilizza AUTOINCREMENT, MySQL utilizza AUTO_INCREMENT

Ecco uno script Perl modificato molto semplice che funziona Mio dataset e controlla molte più di queste condizioni rispetto ad altri script Perl che ho trovato sul web.Nu garantisce che funzionerà per i tuoi dati, ma sentiti libero di modificare e pubblicare di nuovo qui.

#! /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;
    }
}

Ecco uno script Python, costruito sulla risposta di Shalmanese e sull'aiuto di Alex Martelli su Tradurre Perl in Python

Sto creando un wiki della community, quindi sentiti libero di modificare e rifattorizzare finché non interrompe la funzionalità (per fortuna possiamo semplicemente eseguire il rollback) - È piuttosto brutto ma funziona

utilizzare in questo modo (assumendo che lo script si chiami dump_for_mysql.py:

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

Che puoi quindi importare in mysql

nota: è necessario aggiungere manualmente i vincoli di chiave esterna poiché sqlite in realtà non li supporta

ecco la sceneggiatura:

#!/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,

È complicato perché i file di dump sono specifici del fornitore del database.

Se stai usando Rails, esiste un ottimo plugin per questo.Leggere: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/

Aggiornamento

Forcella attualmente mantenuta: https://github.com/ludicast/yaml_db

MySQL Workbench (licenza GPL) viene migrato da SQLite molto facilmente tramite il file Procedura guidata per la migrazione del database.Si installa su Windows, Ubuntu, RHEL, Fedora e OS X.

Sorpreso che nessuno ne abbia parlato ormai, ma in realtà c'è uno strumento esplicitamente per questo.È in perl, SQL:Translator:http://sqlfairy.sourceforge.net/

Converte tra quasi tutte le forme di dati tabulari (diversi formati SQL, fogli di calcolo Excel) e crea persino diagrammi del tuo schema 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

Ho appena seguito questo processo e in questa sessione di domande/risposte sono presenti molto aiuto e informazioni di ottimo livello, ma ho scoperto che dovevo mettere insieme vari elementi (più alcuni provenienti da altre domande/risposte) per ottenere una soluzione funzionante per poter migrare con successo.

Tuttavia, anche dopo aver combinato le risposte esistenti, ho scoperto che lo script Python non funzionava completamente per me poiché non funzionava dove erano presenti più occorrenze booleane in un INSERT.Vedere Qui perché è stato così.

Quindi, ho pensato di pubblicare qui la mia risposta unita.Il merito va ovviamente a coloro che hanno contribuito altrove.Ma volevo restituire qualcosa e far risparmiare agli altri il tempo che segue.

Pubblicherò lo script qui sotto.Ma prima ecco le istruzioni per una conversione...

Ho eseguito lo script su OS X 10.7.5 Lion.Python ha funzionato fuori dagli schemi.

Per generare il file di input MySQL dal database SQLite3 esistente, esegui lo script sui tuoi file come segue,

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

Ho quindi copiato il file dumped_sql.sql risultante su una macchina Linux con Ubuntu 10.04.4 LTS dove doveva risiedere il mio database MySQL.

Un altro problema che ho riscontrato durante l'importazione del file MySQL è stato che alcuni caratteri Unicode UTF-8 (in particolare le virgolette singole) non venivano importati correttamente, quindi ho dovuto aggiungere un'opzione al comando per specificare UTF-8.

Il comando risultante per inserire i dati in un nuovo database MySQL vuoto è il seguente:

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

Lascia cuocere e dovrebbe essere tutto!Non dimenticare di controllare attentamente i tuoi dati, prima e dopo.

Quindi, come richiesto dall'OP, è semplice e veloce, quando sai come!:-)

Per inciso, una cosa di cui non ero sicuro prima di esaminare questa migrazione era se i valori dei campi create_at e aggiornato_at sarebbero stati preservati: la buona notizia per me è che lo sono, quindi ho potuto migrare i miei dati di produzione esistenti.

Buona fortuna!

AGGIORNAMENTO

Da quando ho effettuato questo passaggio, ho notato un problema che non avevo notato prima.Nella mia applicazione Rails, i miei campi di testo sono definiti come "stringa" e questo si trasmette allo schema del database.Il processo qui descritto fa sì che questi vengano definiti come VARCHAR(255) nel database MySQL.Ciò pone un limite di 255 caratteri alle dimensioni di questi campi e tutto ciò che va oltre questo limite viene troncato silenziosamente durante l'importazione.Per supportare una lunghezza del testo maggiore di 255, credo che lo schema MySQL dovrebbe utilizzare "TEXT" anziché VARCHAR(255).Il processo qui definito non include questa conversione.


Ecco lo script Python unito e rivisto che ha funzionato per i miei dati:

#!/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,

Probabilmente il modo più semplice e veloce è utilizzare il comando sqlite .dump, in questo caso creare un dump del database di esempio.

sqlite3 sample.db .dump > dump.sql

Puoi quindi (in teoria) importarlo nel database mysql, in questo caso il database di test sul server database 127.0.0.1, utilizzando l'utente root.

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

Dico in teoria perché ci sono alcune differenze tra le grammatiche.

In sqlite iniziano le transazioni

BEGIN TRANSACTION;
...
COMMIT;

MySQL utilizza solo

BEGIN;
...
COMMIT;

Ci sono altri problemi simili (mi vengono in mente i varchar e le virgolette doppie) ma nulla che la ricerca e la sostituzione non possa risolvere.

Forse dovresti chiederti perché stai migrando, se le prestazioni/dimensioni del database sono il problema, forse prova a riorganizzare lo schema, se il sistema sta passando a un prodotto più potente questo potrebbe essere il momento ideale per pianificare il futuro dei tuoi dati.

Se stai usando Python/Django è abbastanza semplice:

crea due database in settings.py (come qui https://docs.djangoproject.com/en/1.11/topics/db/multi-db/)

allora fai così:

objlist = ModelObject.objects.using('sqlite').all()

for obj in objlist:
    obj.save(using='mysql')

Di recente ho dovuto migrare da MySQL a JavaDB per un progetto su cui sta lavorando il nostro team.Ho trovato un Libreria Java scritta da Apache chiamata DdlUtils questo ha reso tutto abbastanza facile.Fornisce un'API che ti consente di eseguire le seguenti operazioni:

  1. Scopri lo schema di un database ed esportalo come file XML.
  2. Modifica un DB in base a questo schema.
  3. Importa record da un DB all'altro, presupponendo che abbiano lo stesso schema.

Gli strumenti che abbiamo ottenuto non erano completamente automatizzati, ma funzionavano abbastanza bene.Anche se la tua applicazione non è in Java, non dovrebbe essere troppo difficile creare alcuni piccoli strumenti per eseguire una migrazione una tantum.Penso di essere riuscito a portare a termine la nostra migrazione con meno di 150 righe di codice.

Ottieni un dump SQL

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

Importa dump in MySQL

Per piccole importazioni:

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

Questo ti richiederà una password.Notare che:Se vuoi inserire direttamente la password, devi farlo SENZA spazio, subito dopo -p:

mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql

Per discariche più grandi:

mysqlimport o altri strumenti di importazione come BigDump.

BigDump ti offre una barra di avanzamento:

enter image description here

Lo script Python ha funzionato dopo alcune modifiche come segue:

# 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('"', "'")

...

Non è necessario alcun script, comando, ecc...

devi esportare il tuo database sqlite solo come file .csv file e quindi importarlo in Mysql utilizzando phpmyadmin.

L'ho usato e ha funzionato benissimo...

Utilizzo il caricatore dati per la migrazione di quasi tutti i dati, mi aiuta a convertire MSSQL in MYSQL, MS access in MSSQL, mysql, csv loader, foxpro e MSSQL in MS access, MYSQl, CSV, foxpro ecc.A mio avviso questo è il miglior strumento di migrazione dei dati

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

Basato sulla soluzione di Jims:Un modo semplice e veloce per migrare SQLite3 su 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  

Questo funziona per me.Uso sed solo per lanciare la prima riga, che non è simile a mysql, ma potresti anche modificare lo script dump.py per buttare via questa riga.

Ah...Vorrei averlo trovato prima!La mia risposta è stata a questo post... script per convertire il file mysql dump sql in un formato che può essere importato in sqlite3 db

Combinare i due sarebbe esattamente ciò di cui avevo bisogno:


Quando il database sqlite3 verrà utilizzato con Ruby potresti voler modificare:

tinyint([0-9]*) 

A:

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

ahimè, funziona solo a metà perché anche se stai inserendo 1 e 0 in un campo contrassegnato come booleano, sqlite3 li memorizza come 1 e 0 quindi devi passare e fare qualcosa del tipo:

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)

ma è stato utile avere il file SQL da esaminare per trovare tutti i valori booleani.

Fallino ha identificato correttamente la posizione dell'errore nello script.Ho la soluzione.Il problema sono le seguenti righe:

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

Il modello di sostituzione (2° parametro) nelle chiamate re.sub è una stringa "normale", quindi invece di \1 espandersi alla prima corrispondenza regexp, si espande in un letterale 0x01.Allo stesso modo, \2 si espande in 0x02.Ad esempio, una riga contenente:, 't', 'f', verrebbe sostituito con:10
(Prima modifica di sostituzione, 'T', a <0x1> 1 <0x2> Seconda variazione di sostituzione <0x02> 'f', a <0x1> 0 <0x1>)

La soluzione consiste nel modificare le stringhe sostitutive aggiungendo un prefisso "r" o eseguendo l'escape di \1 e \2 nella stringa esistente.Poiché la facile manipolazione delle stringhe regexp è lo scopo delle stringhe grezze, ecco la soluzione utilizzando quelle:

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

questo software pronto all'uso funziona per me.provalo e fai sapere agli altri.

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

Inoltre:

Ho dovuto fare una piccola modifica:in qualche modo l'incremento_automatico di un campo (un campo trovato dal messaggio di errore) non era abilitato.Quindi in phpmyadmin controllo la proprietà A_I di questo campo e funziona completamente.Spero che sia d'aiuto.

Dunn.

Ho scritto questo semplice script in Python3.Può essere utilizzato come classe inclusa o script autonomo richiamato tramite una shell terminale.Per impostazione predefinita importa tutti i numeri interi come int(11)e stringhe come varchar(300), ma tutto ciò può essere regolato rispettivamente negli argomenti del costruttore o dello script.

NOTA: Richiede MySQL Connector/Python 2.0.4 o versione successiva

Ecco un collegamento alla fonte su GitHub se trovi difficile leggere il codice seguente: 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()

Di solito uso il Tabelle di esportazione/importazione caratteristica di IntelliJ DataGrip.

step 1 step 2 step 3

Puoi vedere i progressi nell'angolo in basso a destra.

[enter image description here]

Questo script è ok tranne che per questo caso che ovviamente ho incontrato:

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

Lo script dovrebbe fornire questo output:

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

Ma dà invece quell'output:

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

con alcuni strani caratteri non ascii intorno agli ultimi 0 e 1.

Questo non si è più verificato quando ho commentato le seguenti righe di codice (43-46) ma sono comparsi altri problemi:


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

Questo è solo un caso speciale, quando vogliamo aggiungere un valore come "f" o "t" ma non mi sento molto a mio agio con le espressioni regolari, volevo solo individuare questo caso per essere corretto da qualcuno.

Comunque grazie mille per quel pratico script!!!

Questa semplice soluzione ha funzionato per me:

<?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 ) );
    }
}

Ho preso lo script Python da https://stackoverflow.com/a/32243979/746459 (sopra) e risolto il problema per far fronte ai nostri schemi SQLite.C'erano alcuni problemi da affrontare.

Puoi trovarlo nel controllo del codice sorgente qui: https://bitbucket.org/mjogltd/sqlite3mysql

È disponibile anche la stessa cosa racchiusa come immagine Docker, qui: https://hub.docker.com/r/mjog/sqlite3mysql/ - è completamente utilizzabile anche su un desktop Windows.

Ho controllato attentamente tutte le risposte in questo post, così come le risposte in un altro post correlato Tradurre Perl in Python.Eppure nessuno poteva risolvere completamente il mio problema.

Il mio scenario è che devo migrare un database di Trac da SQLite a MySQL e il database contiene molti contenuti wiki basati sulla tecnologia.Pertanto all'interno del INSERT INTO valori, potrebbero esserci istruzioni SQL come CREATE TABLE E AUTOINCREMENT.Ma la sostituzione riga per riga potrebbe contenere sostituzioni errate.

Alla fine ho scritto il mio strumento per questo scopo:

https://github.com/motherapp/sqlite_sql_parser

L'utilizzo è relativamente semplice:

python parse_sqlite_sql.py export.sql

Verrebbero generati due file: export.sql.schema.sql E export.sql.data.sql.Uno per lo schema DB aggiornato e l'altro per i dati DB aggiornati.

È possibile apportare ulteriori modifiche manuali al file di schema DB utilizzando qualsiasi editor di testo, senza preoccuparsi di modificare il contenuto.

Spero che possa aiutare gli altri in futuro.

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

fai attenzione alle istruzioni CREATE

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top