Pergunta

Alguém conhece uma maneira rápida e fácil de migrar um banco de dados SQLite3 para MySQL?

Foi útil?

Solução

Aqui está uma lista de conversores (não atualizado desde 2011):


Um método alternativo que funcionaria bem, mas raramente é mencionado, é:use uma classe ORM que abstraia diferenças específicas do banco de dados para você.por exemplo.você obtém isso em PHP (Feijão vermelho), Python (camada ORM do Django, Tempestade, SqlAlchemy), Ruby on Rails (Registro ativo), Cacau (Dados principais)

ou sejavocê poderia fazer isso:

  1. Carregue dados do banco de dados de origem usando a classe ORM.
  2. Armazene dados na memória ou serialize em disco.
  3. Armazene dados no banco de dados de destino usando a classe ORM.

Outras dicas

Todo mundo parece começar com algumas expressões greps e perl e você meio que consegue algo que funciona para o seu conjunto de dados específico, mas não tem ideia se os dados foram importados corretamente ou não.Estou seriamente surpreso que ninguém tenha construído uma biblioteca sólida que possa converter entre os dois.

Aqui está uma lista de TODAS as diferenças na sintaxe SQL que conheço entre os dois formatos de arquivo:As linhas que começam com:

  • INICIAR TRANSAÇÃO
  • COMPROMETER-SE
  • sqlite_sequence
  • CRIAR ÍNDICE ÚNICO

não são usados ​​no MySQL

  • SQLlite usa CREATE TABLE/INSERT INTO "table_name" e MySQL usa CREATE TABLE/INSERT INTO table_name
  • MySQL não usa aspas dentro da definição do esquema
  • MySQL usa aspas simples para strings dentro do INSERT INTO cláusulas
  • SQLlite e MySQL têm maneiras diferentes de escapar de strings dentro INSERT INTO cláusulas
  • SQLlite usa 't' e 'f' para booleanos, o MySQL usa 1 e 0 (uma regex simples para isso pode falhar quando você tem uma string como:'Eu aceito, você não' dentro do seu INSERT INTO)
  • SQLLite usa AUTOINCREMENT, MySQL usa AUTO_INCREMENT

Aqui está um script perl hackeado muito básico que funciona para meu conjunto de dados e verifica muito mais dessas condições do que outros scripts Perl que encontrei na web.Nu garante que funcionará para seus dados, mas fique à vontade para modificar e postar de volta aqui.

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

Aqui está um script python, construído a partir da resposta de Shalmanese e da ajuda de Alex Martelli em Traduzindo Perl para Python

Estou criando um wiki da comunidade, então sinta-se à vontade para editar e refatorar, desde que não prejudique a funcionalidade (felizmente, podemos simplesmente reverter) - É muito feio, mas funciona

use assim (assumindo que o script seja chamado dump_for_mysql.py:

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

Que você pode importar para o mysql

nota - você precisa adicionar restrições de chave estrangeira manualmente, pois o sqlite não as suporta

aqui está o roteiro:

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

É confuso porque os arquivos de despejo são específicos do fornecedor do banco de dados.

Se você estiver usando Rails, existe um ótimo plugin para isso.Ler: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/

Atualizar

Garfo atualmente mantido: https://github.com/ludicast/yaml_db

MySQL Workbench (licença GPL) migra do SQLite muito facilmente através do Assistente de migração de banco de dados.Instala em Windows, Ubuntu, RHEL, Fedora e OS X.

Surpreso que ninguém tenha mencionado isso até agora, mas na verdade existe uma ferramenta explicitamente para isso.Está em perl, SQL:Translator:http://sqlfairy.sourceforge.net/

Converte praticamente qualquer forma de dados tabulares (diferentes formatos SQL, planilha do Excel) e até faz diagramas do seu esquema 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

Acabei de passar por esse processo e há muita ajuda e informações muito boas nestas perguntas e respostas, mas descobri que precisava reunir vários elementos (além de alguns de outras perguntas e respostas) para obter uma solução funcional em para migrar com sucesso.

No entanto, mesmo depois de combinar as respostas existentes, descobri que o script Python não funcionou totalmente para mim, pois não funcionou onde havia múltiplas ocorrências booleanas em um INSERT.Ver aqui por que foi esse o caso.

Então, pensei em postar minha resposta mesclada aqui.O crédito vai para aqueles que contribuíram em outros lugares, é claro.Mas eu queria retribuir e economizar o tempo dos outros.

Vou postar o script abaixo.Mas primeiro, aqui estão as instruções para uma conversão...

Executei o script no OS X 10.7.5 Lion.Python funcionou imediatamente.

Para gerar o arquivo de entrada MySQL a partir de seu banco de dados SQLite3 existente, execute o script em seus próprios arquivos da seguinte forma,

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

Em seguida, copiei o arquivo dumped_sql.sql resultante para uma caixa Linux executando o Ubuntu 10.04.4 LTS, onde meu banco de dados MySQL residiria.

Outro problema que tive ao importar o arquivo MySQL foi que alguns caracteres Unicode UTF-8 (especificamente aspas simples) não estavam sendo importados corretamente, então tive que adicionar uma opção ao comando para especificar UTF-8.

O comando resultante para inserir os dados em um novo banco de dados MySQL vazio é o seguinte:

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

Deixe cozinhar e pronto!Não se esqueça de examinar seus dados, antes e depois.

Então, conforme solicitado pelo OP, é rápido e fácil, quando você sabe!:-)

Além disso, uma coisa que eu não tinha certeza antes de analisar essa migração era se os valores dos campos create_at e update_at seriam preservados - a boa notícia para mim é que sim, para que eu pudesse migrar meus dados de produção existentes.

Boa sorte!

ATUALIZAR

Desde que fiz essa mudança, percebi um problema que não havia notado antes.Na minha aplicação Rails, meus campos de texto são definidos como 'string' e isso é transferido para o esquema do banco de dados.O processo descrito aqui resulta na definição deles como VARCHAR(255) no banco de dados MySQL.Isso coloca um limite de 255 caracteres nesses tamanhos de campo - e qualquer coisa além disso foi truncada silenciosamente durante a importação.Para suportar comprimento de texto maior que 255, o esquema MySQL precisaria usar 'TEXT' em vez de VARCHAR(255), acredito.O processo aqui definido não inclui esta conversão.


Aqui está o script Python mesclado e revisado que funcionou para meus dados:

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

Provavelmente a maneira mais fácil e rápida é usar o comando sqlite .dump; neste caso, crie um dump do banco de dados de amostra.

sqlite3 sample.db .dump > dump.sql

Você pode então (em teoria) importar isso para o banco de dados mysql, neste caso o banco de dados de teste no servidor de banco de dados 127.0.0.1, usando o usuário root.

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

Digo em teoria porque existem algumas diferenças entre as gramáticas.

No sqlite as transações começam

BEGIN TRANSACTION;
...
COMMIT;

MySQL usa apenas

BEGIN;
...
COMMIT;

Existem outros problemas semelhantes (varchars e aspas duplas voltam à mente), mas nada que localizar e substituir não possa resolver.

Talvez você deva perguntar por que está migrando, se o desempenho/tamanho do banco de dados é o problema, talvez considere reoginizar o esquema, se o sistema estiver migrando para um produto mais poderoso, este pode ser o momento ideal para planejar o futuro de seus dados.

Se você estiver usando Python/Django é bem fácil:

crie dois bancos de dados em settings.py (como aqui https://docs.djangoproject.com/en/1.11/topics/db/multi-db/)

então é só fazer assim:

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

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

Recentemente tive que migrar do MySQL para o JavaDB para um projeto no qual nossa equipe está trabalhando.Achei um Biblioteca Java escrita pelo Apache chamada DdlUtils isso tornou isso muito fácil.Ele fornece uma API que permite fazer o seguinte:

  1. Descubra o esquema de um banco de dados e exporte-o como um arquivo XML.
  2. Modifique um banco de dados com base neste esquema.
  3. Importe registros de um banco de dados para outro, assumindo que tenham o mesmo esquema.

As ferramentas que criamos não eram totalmente automatizadas, mas funcionavam muito bem.Mesmo que seu aplicativo não esteja em Java, não deverá ser muito difícil preparar algumas pequenas ferramentas para fazer uma migração única.Acho que consegui realizar nossa migração com menos de 150 linhas de código.

Obtenha um despejo SQL

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

Importar dump para MySQL

Para pequenas importações:

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

ou

mysql -u root -p somedb < myTemporarySQLFile.sql

Isso solicitará uma senha.Observe:Se quiser inserir sua senha diretamente, deverá fazê-lo SEM espaço, logo após -p:

mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql

Para lixões maiores:

mysqlimport ou outras ferramentas de importação como Grande Dump.

BigDump oferece uma barra de progresso:

enter image description here

O script python funcionou após algumas modificações da seguinte forma:

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

...

Não há necessidade de nenhum script, comando, etc ...

você só precisa exportar seu banco de dados sqlite como um .csv arquivo e depois importe-o no Mysql usando phpmyadmin.

Eu usei e funcionou maravilhosamente...

Eu uso o carregador de dados para migrar quase todos os dados, ele me ajuda a converter MSSQL para MYSQL, acesso MS para MSSQL, mysql, carregador csv, foxpro e MSSQL para acesso MS, MYSQl, CSV, foxpro etc.Na minha opinião, esta é a melhor ferramenta de migração de dados

Download grátis : http://www.dbload.com

Com base na solução de Jims:Maneira rápida e fácil de migrar SQLite3 para 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  

Isso funciona para mim.Eu uso sed apenas para lançar a primeira linha, o que não é semelhante ao mysql, mas você também pode modificar o script dump.py para descartar essa linha.

Ha...Eu gostaria de ter encontrado isso primeiro!Minha resposta foi para esse post... script para converter o arquivo sql dump mysql em um formato que pode ser importado para sqlite3 db

Combinar os dois seria exatamente o que eu precisava:


Quando o banco de dados sqlite3 for usado com Ruby você pode querer alterar:

tinyint([0-9]*) 

para:

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

infelizmente, isso funciona apenas pela metade porque mesmo que você esteja inserindo 1 e 0 em um campo marcado como booleano, o sqlite3 os armazena como 1 e 0, então você precisa passar e fazer 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)

mas foi útil ter o arquivo sql para procurar todos os booleanos.

fallino identificou corretamente a localização do erro no script.Eu tenho a solução.O problema são as seguintes linhas:

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

O padrão de substituição (2º parâmetro) nas chamadas re.sub é uma string "normal", portanto, em vez de \1 expandir para a primeira correspondência de regexp, ele se expande para um literal 0x01.Da mesma forma, \2 se expande para 0x02.Por exemplo, uma linha contendo:, 't', 'f', seria substituído por:10
(Primeira substituição muda, 't', para <0x1> 1 <0x2> Segunda substituição alterações u0002 'f', para <0x1> 0 <0x1>)

A correção é alterar as strings de substituição adicionando um prefixo 'r' ou escapando de \1 e \2 na string existente.Como a manipulação fácil de strings regexp é a finalidade das strings brutas, aqui está a correção usando-as:

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

este software pronto para uso - funciona para mim.experimente e deixe outros saberem.

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

Além disso:

Tive que fazer uma pequena mudança:de alguma forma, o incremento automático de um campo (um campo encontrado na mensagem de erro) não foi habilitado.Então no phpmyadmin eu verifico a propriedade A_I deste campo e funciona completamente.Espero que ajude.

Não.

Escrevi este script simples em Python3.Ele pode ser usado como uma classe incluída ou um script independente invocado por meio de um terminal.Por padrão, ele importa todos os números inteiros como int(11)e cordas como varchar(300), mas tudo isso pode ser ajustado nos argumentos do construtor ou do script, respectivamente.

OBSERVAÇÃO: Requer MySQL Connector/Python 2.0.4 ou superior

Aqui está um link para a fonte no GitHub se você achar o código abaixo difícil de ler: 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()

Eu costumo usar o Exportar/importar tabelas característica de IntelliJ DataGrip.

step 1 step 2 step 3

Você pode ver o progresso no canto inferior direito.

[enter image description here]

Este script está ok, exceto neste caso que, claro, eu conheci:

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

O script deve fornecer esta saída:

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

Mas fornece essa saída:

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

com alguns caracteres não-ascii estranhos em torno dos últimos 0 e 1.

Isso não apareceu mais quando comentei as seguintes linhas do código (43-46) mas apareceram outros 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 é apenas um caso especial, quando queremos adicionar um valor como 'f' ou 't', mas não estou muito confortável com expressões regulares, só queria identificar esse caso para ser corrigido por alguém.

De qualquer forma, muito obrigado por esse script útil !!!

Esta solução simples funcionou para mim:

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

Eu peguei o script Python de https://stackoverflow.com/a/32243979/746459 (acima) e corrigi-lo para lidar com nossos próprios esquemas sqlite.Havia alguns problemas para resolver.

Você pode encontrá-lo no controle de origem aqui: https://bitbucket.org/mjogltd/sqlite3mysql

Também está disponível a mesma coisa encapsulada como uma imagem Docker, aqui: https://hub.docker.com/r/mjog/sqlite3mysql/ - é totalmente utilizável mesmo em uma área de trabalho do Windows.

Verifiquei cuidadosamente todas as respostas nesta postagem, bem como as respostas em outra postagem relacionada Traduzindo Perl para Python.No entanto, ninguém conseguiu resolver totalmente o meu problema.

Meu cenário é que preciso migrar um banco de dados Trac do sqlite para MySQL, e o banco de dados contém muito conteúdo wiki baseado em tecnologia.Portanto dentro do INSERT INTO valores, pode haver instruções SQL como CREATE TABLE e AUTOINCREMENT.Mas a substituição linha por linha pode conter substituições erradas.

Eventualmente, escrevi minha própria ferramenta para esse propósito:

https://github.com/motherapp/sqlite_sql_parser

O uso é relativamente simples:

python parse_sqlite_sql.py export.sql

Dois arquivos seriam gerados: export.sql.schema.sql e export.sql.data.sql.Um para esquema de banco de dados atualizado e outro para dados de banco de dados atualizados.

Seria possível fazer modificações manuais adicionais no arquivo de esquema do banco de dados usando qualquer editor de texto, sem se preocupar em alterar o conteúdo.

Espero que possa ajudar outras pessoas no futuro.

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

cuidado com as declarações CREATE

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top