Un modo semplice e rapido per migrare SQLite3 in MySQL?

Qualcuno conosce un modo facile e veloce per migrare un database SQLite3 in MySQL?

Ecco una lista di convertitori (non aggiornati dal 2011):


Un metodo alternativo che funziona bene ma viene raramente menzionato è: utilizzare una class ORM che astrae specifiche differenze di database per te. es. ottieni questi in PHP ( RedBean ), Python (strato ORM di Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )

cioè si potrebbe fare questo:

  1. Carica i dati dal database di origine utilizzando la class ORM.
  2. Memorizza i dati in memoria o serializza su disco.
  3. Memorizza i dati nel database di destinazione utilizzando la class ORM.

Ognuno sembra iniziare con alcune espressioni greps e perl e si ottiene qualcosa che funziona per il proprio set di dati particolare, ma non si ha idea se i dati siano stati importati correttamente o meno. Sono seriamente sorpreso che nessuno abbia costruito una libreria solida in grado di convertire tra i due.

Ecco una lista di TUTTE le differenze nella syntax SQL che conosco tra i due formati di file: Le righe che iniziano con:

  • INIZIA LA TRANSAZIONE
  • COMMETTERE
  • sqlite_sequence
  • CREA UN INDICE UNICO

non sono usati in MySQL

  • SQLlite utilizza CREATE TABLE / INSERT INTO “nome_tabella” e MySQL utilizza CREATE TABLE / INSERT INTO nome_tabella
  • MySQL non usa virgolette all’interno della definizione dello schema
  • MySQL usa le virgolette singole per le stringhe all’interno delle clausole INSERT INTO
  • SQLlite e MySQL hanno diversi modi di escaping delle stringhe all’interno delle clausole INSERT INTO
  • SQLlite usa ‘t’ e ‘f’ per i booleani, MySQL usa 1 e 0 (una semplice regex per questo può fallire quando si ha una stringa del tipo: ‘Io sì, non ci si trova all’interno di INSERT INTO)
  • SQLLite utilizza AUTOINCREMENT, MySQL utilizza AUTO_INCREMENT

Ecco uno script perl hacked molto semplice che funziona per il mio set di dati e controlla molte altre di queste condizioni che altri script perl ho trovato sul web. Nu garantisce che funzionerà per i tuoi dati, ma sentiti libero di modificare e postare 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, basato sulla risposta di Shalmanese e sull’aiuto di Alex martelli su Translating Perl to Python

Lo sto facendo wiki della comunità, quindi per favore sentiti libero di modificare e refactare fino a quando non rompere la funzionalità (per fortuna possiamo solo tornare indietro) – È piuttosto brutto ma funziona

usare in questo modo (assumendo che lo script sia chiamato 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 non li supporta effettivamente

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 per i database.

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

Aggiornare

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

Sorpreso, nessuno lo ha già detto, ma in realtà c’è uno strumento esplicitamente per questo. È in perl, SQL: Translator: http://sqlfairy.sourceforge.net/

Converte tra la maggior parte qualsiasi forma di dati tabulari (formati SQL diversi, foglio di calcolo Excel) e persino crea 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 svolto questo processo e in questo Q / A ci sono molti ottimi consigli e informazioni, ma ho scoperto che dovevo riunire vari elementi (più alcuni di altri Q / A) per ottenere una soluzione funzionante in ordine per migrare con successo.

Tuttavia, anche dopo aver combinato le risposte esistenti, ho scoperto che lo script Python non funzionava completamente perché non funzionava dove c’erano più occorrenze booleane in un INSERT. Vedi qui perché era così.

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

Pubblicherò la sceneggiatura qui sotto. Ma in primo luogo, ecco le istruzioni per una conversione …

Ho eseguito lo script su OS X 10.7.5 Lion. Python ha lavorato fuori dalla scatola.

Per generare il file di input MySQL dal tuo 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 in cui il mio database MySQL doveva risiedere.

Un altro problema che ho riscontrato durante l’importazione del file MySQL era che alcuni caratteri unicode UTF-8 (in particolare virgolette singole) non venivano importati correttamente, quindi ho dovuto aggiungere un commutatore 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 che cucini, e dovrebbe essere così! Non dimenticare di controllare i dati, prima e dopo.

Quindi, come richiesto dall'OP, è facile e veloce, quando sai come! 🙂

Per inciso, una cosa di cui non ero sicuro prima di esaminare questa migrazione era se i valori del campo created_at e updated_at venissero conservati - la buona notizia per me è che lo sono, quindi potrei migrare i miei dati di produzione esistenti.

In bocca al lupo!

AGGIORNARE

Da quando ho fatto 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 ciò viene portato allo schema del database. Il processo descritto qui risulta definito come VARCHAR (255) nel database MySQL. Ciò pone un limite di 255 caratteri su queste dimensioni di campo e qualsiasi cosa oltre questa viene troncata silenziosamente durante l'importazione. Per supportare una lunghezza del testo maggiore di 255, credo che lo schema MySQL debba utilizzare "TEXT" piuttosto che VARCHAR (255). Il processo qui definito non include questa conversione.


Ecco lo script Python unito e modificato 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"(? 

Recentemente ho dovuto migrare da MySQL a JavaDB per un progetto su cui il nostro team sta lavorando. Ho trovato una libreria Java scritta da Apache chiamata DdlUtils che lo ha reso piuttosto facile. Fornisce un’API che ti permette di fare quanto segue:

  1. Scopri lo schema di un database ed esportalo come file XML.
  2. Modifica un DB basato su questo schema.
  3. Importa i record da un DB all’altro, assumendo che abbiano lo stesso schema.

Gli strumenti con cui siamo finiti non erano completamente automatizzati, ma hanno funzionato piuttosto bene. Anche se la tua applicazione non è in Java, non dovrebbe essere troppo difficile montare alcuni piccoli strumenti per eseguire una singola migrazione. Penso di essere stato in grado di estrarre la nostra migrazione con meno di 150 righe di codice.

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

 sqlite3 sample.db .dump > dump.sql 

È quindi ansible (in teoria) importarlo nel database mysql, in questo caso il database di test sul server di database 127.0.0.1, utilizzando la radice utente.

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

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

In transazioni sqlite iniziano

 BEGIN TRANSACTION; ... COMMIT; 

MySQL usa solo

 BEGIN; ... COMMIT; 

Ci sono altri problemi simili (i richiami di varchar e virgolette mi vengono in mente di nuovo) ma niente di trovare e sostituire non può essere risolto.

Forse dovresti chiederti perché stai migrando, se la dimensione delle prestazioni / del database è il problema, forse guarda a riesaminare lo schema, se il sistema si sta spostando su un prodotto più potente questo potrebbe essere il momento ideale per pianificare il futuro dei tuoi dati.

Ottieni un dump SQL

 [email protected]$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql 

Importa dump su MySQL

Per piccole importazioni:

 [email protected]$ mysql -u  -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. Nota: se vuoi inserire la tua password direttamente, 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:

inserisci la descrizione dell'immagine qui

Se stai usando Python / Django è piuttosto facile:

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

quindi fai come questo:

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

MySQL Workbench (licenza GPL) migra da SQLite molto facilmente tramite la procedura guidata Migrazione database . Installa su Windows, Ubuntu, RHEL, Fedora e OS X.

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

Utilizzo il caricatore di dati per la migrazione di quasi tutti i dati, mi aiuta a convertire MSSQL in MYSQL, accesso MS a MSSQL, mysql, csv loader, foxpro e MSSQL a MS Access, MYSQl, CSV, foxpro ecc. Secondo me questo è il migliore Strumento di migrazione dei dati

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

Basato sulla soluzione di Jims: un modo semplice e rapido per migrare SQLite3 in 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. Io uso sed solo per lanciare la prima riga, che non è simile a mysql, ma si potrebbe anche modificare lo script dump.py per lanciare questa linea.

Ha … Vorrei averlo trovato per primo! La mia risposta è stata a questo post … script per convertire mysql dump sql in un formato che può essere importato in sqlite3 db

Combinare i due sarebbe esattamente quello di cui avevo bisogno:


Quando il database sqlite3 verrà utilizzato con ruby, potresti voler cambiare:

 tinyint([0-9]*) 

a:

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

ahimè, questo 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 cercare per trovare tutti i booleani.

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

 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 pattern di sostituzione (2 ° parametro) nelle chiamate re.sub è una stringa “normale”, quindi anziché espandersi \ 1 alla prima corrispondenza regexp, si espande in un valore letterale 0x01. Allo stesso modo, \ 2 si espande a 0x02. Ad esempio, una riga contenente:, ‘t’, ‘f’, verrebbe sostituita con: <0x01> 10 <0x02>
(Le prime modifiche di sostituzione, ‘t’, a <0x1> 1 <0x2> Le modifiche di sostituzione secondarie <0x02> ‘f’, a <0x1> 0 <0x1>)

La correzione consiste nel modificare le stringhe di sostituzione aggiungendo un prefisso “r” o eseguendo l’escape di \ 1 e \ 2 nella stringa esistente. Dal momento che la semplice manipolazione delle stringhe regexp è ciò che le stringhe raw sono, ecco la correzione usando 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 fuori dalla scatola – funziona per me. provalo e fai sapere ad altri.

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

Inoltre:

Ho dovuto fare una piccola modifica: in qualche modo l’auto_increment 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.

Non c’è bisogno di script, comandi, ecc …

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

L’ho usato e ha funzionato fantastico …

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

 INSERISCI IN VALORI "requestcomparison_stopword" (149, 'f');
 INSERISCI IN VALORI "requestcomparison_stopword" (420, 't');

Lo script dovrebbe dare questo risultato:

 INSERIRE in requestcomparison_stopword VALUES (149, 'f');
 INSERISCI NEI VALORI di requestcomparison_stopword (420, 't');

Ma dà invece quell’output:

 INSERISCI NEI VALORI di requestcomparison_stopword (1490;
 INSERISCI NEI VALORI di requestcomparison_stopword (4201;

con alcuni strani caratteri non ASCII attorno agli ultimi 0 e 1.

Questo non si è più verificato quando ho commentato le seguenti righe del codice (43-46) ma sono apparsi 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 “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 quella comoda sceneggiatura !!!

Questa semplice soluzione ha funzionato per me:

 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 l’ho risolto per far fronte ai nostri schemi sqlite. C’erano alcuni problemi da affrontare.

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

Anche disponibile è la stessa cosa avvolta da un’immagine Docker, qui: https://hub.docker.com/r/mjog/sqlite3mysql/ – è completamente utilizzabile anche su un desktop Windows.

Ho scritto questo semplice script in Python3. Può essere usato come una class inclusa o uno script autonomo invocato tramite una shell di terminale. Per impostazione predefinita importa tutti gli interi come int(11) e stringhe come varchar(300) , ma tutto ciò che può essere regolato rispettivamente negli argomenti del costruttore o dello script.

NOTA: richiede MySQL Connector / Python 2.0.4 o versioni successive

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

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

Il mio scenario è che ho bisogno di migrare un database di Trac da sqlite a MySQL, e il database contiene molti contenuti wiki basati sulla tecnologia. Pertanto, all’interno dei valori INSERT INTO , potrebbero essere presenti istruzioni SQL come CREATE TABLE e AUTOINCREMENT . Ma la sostituzione linea per linea potrebbe avere sostituzioni errate lì.

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 ed export.sql.data.sql . Uno per lo schema DB aggiornato e l’altro per i dati DB aggiornati.

Si potrebbero fare ulteriori modifiche manuali sul file dello schema DB usando qualsiasi editor di testo, senza preoccuparsi di cambiare il contenuto.

Spero che possa aiutare gli altri in futuro.

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

fai attenzione alle istruzioni CREATE