Cara mudah dan mudah untuk memigrasi SQLite3 ke MySQL? [Tutup]

224

Adakah yang tahu cara cepat dan mudah untuk memigrasi basis data SQLite3 ke MySQL?

Stephen Cox
sumber

Jawaban:

62

Berikut adalah daftar konverter (tidak diperbarui sejak 2011):


Metode alternatif yang akan bekerja dengan baik tetapi jarang disebutkan adalah: gunakan kelas ORM yang abstrak perbedaan database tertentu untuk Anda. mis. Anda mendapatkannya di PHP ( RedBean ), Python (lapisan ORM Django, Storm , SqlAlchemy ), Ruby on Rails ( ActiveRecord ), Cocoa ( CoreData )

yaitu Anda bisa melakukan ini:

  1. Memuat data dari database sumber menggunakan kelas ORM.
  2. Menyimpan data dalam memori atau membuat serial ke disk.
  3. Menyimpan data ke dalam basis data tujuan menggunakan kelas ORM.
David d C e Freitas
sumber
107

Semua orang tampaknya memulai dengan beberapa greps dan ekspresi perl dan Anda agak mendapatkan sesuatu yang berfungsi untuk dataset khusus Anda, tetapi Anda tidak tahu apakah itu mengimpor data dengan benar atau tidak. Saya sangat terkejut tidak ada yang membangun perpustakaan yang solid yang dapat mengkonversi antara keduanya.

Berikut daftar SEMUA perbedaan dalam sintaks SQL yang saya ketahui tentang antara dua format file: Baris dimulai dengan:

  • TRANSAKSI AWAL
  • MELAKUKAN
  • sqlite_afterence
  • BUAT INDEKS UNIK

tidak digunakan di MySQL

  • Penggunaan SQLlite CREATE TABLE/INSERT INTO "table_name"dan penggunaan MySQLCREATE TABLE/INSERT INTO table_name
  • MySQL tidak menggunakan kutipan di dalam definisi skema
  • MySQL menggunakan tanda kutip tunggal untuk string di dalam INSERT INTOklausa
  • SQLlite dan MySQL memiliki berbagai cara untuk menghindari string di dalam INSERT INTOklausa
  • Penggunaan SQLlite 't'dan 'f'untuk boolean, penggunaan MySQL 1dan 0(regex sederhana untuk ini dapat gagal ketika Anda memiliki string seperti: 'Saya lakukan, Anda tidak' di dalam Anda INSERT INTO)
  • Penggunaan SQLLite AUTOINCREMENT, menggunakan MySQLAUTO_INCREMENT

Berikut ini adalah skrip perl yang diretas yang sangat dasar yang berfungsi untuk dataset saya dan memeriksa lebih banyak kondisi ini yang ditemukan oleh skrip perl lainnya di web. Nu menjamin bahwa itu akan berfungsi untuk data Anda tetapi jangan ragu untuk memodifikasi dan memposting kembali di sini.

#! /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
sumber
8
Alex martelli melakukan pekerjaan yang baik menulis ulang ini sebagai python di stackoverflow.com/questions/1067060/perl-to-python
Jiaaro
Saya menambahkan skrip python lengkap (skrip perl saja tidak cukup untuk saya ... perlu beberapa pemrosesan tambahan untuk menangani Kunci Asing, dan Indeks)
Jiaaro
Saya menulis ulang jawaban ini pada pertanyaan lain stackoverflow.com/questions/1067060/_/1070463#1070463
Brad Gilbert
2
KOMIT dan BUAT INDEK UNIK adalah perintah MySQL yang valid, mohon perbaiki.
niutech
5
Saya mengerti skrip Anda "cepat dan kotor", tetapi juga sangat berguna, jadi inilah beberapa tambahan / perbaikan bug: * setelah && ($line !~ /CREATE UNIQUE INDEX/)menambahkan && ($line !~ /PRAGMA foreign_keys=OFF/) * tabel-nama-pencocokan regex meleset angka, yang bukannya $line =~ /INSERT INTO \"([a-z_]*)\"(.*)/harus ada $line =~ /INSERT INTO \"([a-z_1-9]*)\"(.*)/ Semoga ini membantu masa depan pembaca
Michał Leon
50

Berikut ini adalah skrip python, yang dibangun dari jawaban Shalman dan beberapa bantuan dari Alex martelli di Penerjemahan Perl ke Python

Saya membuatnya menjadi komunitas wiki, jadi silakan mengedit, dan refactor selama itu tidak merusak fungsionalitasnya (untungnya kami hanya dapat memutar kembali) - Cukup jelek tapi berfungsi

gunakan seperti itu (dengan asumsi skrip disebut dump_for_mysql.py:

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

Yang kemudian dapat Anda impor ke mysql

catatan - Anda perlu menambahkan batasan kunci asing secara manual karena sqlite sebenarnya tidak mendukungnya

ini skripnya:

#!/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
sumber
2
Halo Jim, pada set data saya, setiap pernyataan INSERT pertama dibungkus dengan backquote, bukan dengan kutipan tunggal: __ TABEL DROP JIKA ADA schema_migrations; BUAT MEJA JIKA TIDAK ADA schema_migrations( versionvarchar (255) BUKAN NULL); INSERT INTO schema_migrations VALUES ( 20100714032840); INSERT INTO schema_migrations VALUES ('20100714033251'); __
David
baik ... itu tidak muncul di atas, tetapi tanda kutip mundur muncul di dalam VALUES ([DI SINI] 20100714032840 [/ DI SINI])
David
1
AUTOINCREMENT di Mysql adalah AUTO_INCREMENT. Script tidak menjelaskan hal itu.
giuseppe
Ini tidak berfungsi untuk basis data wiki media. Banyak kesalahan: Blobvartipe data, kutu kembali dalam pernyataan CREATE ...
Frank Hintsch
1
tidak bekerja Mungkin tidak semua kondisi dipertimbangkan ...
Himanshu Bansal
10

Mungkin cara termudah dan cepat adalah menggunakan perintah sqlite .dump, dalam hal ini membuat dump dari database sampel.

sqlite3 sample.db .dump > dump.sql

Anda kemudian dapat (secara teori) mengimpor ini ke dalam database mysql, dalam hal ini database pengujian pada server database 127.0.0.1, menggunakan root pengguna.

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

Saya katakan dalam teori karena ada beberapa perbedaan antara tata bahasa.

Dalam transaksi sqlite dimulai

BEGIN TRANSACTION;
...
COMMIT;

MySQL hanya menggunakan

BEGIN;
...
COMMIT;

Ada masalah serupa lainnya (varchars dan tanda kutip ganda muncul kembali dalam pikiran) tetapi tidak ada yang menemukan dan mengganti tidak dapat memperbaiki.

Mungkin Anda harus bertanya mengapa Anda bermigrasi, jika kinerja / ukuran basis data masalahnya mungkin melihat reoginising skema, jika sistem pindah ke produk yang lebih kuat ini mungkin waktu yang ideal untuk merencanakan masa depan data Anda.

Richard Gourlay
sumber
2
tetapi tugas yang paling sulit adalah perbedaan antara tata bahasa mingguan
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
sumber
7

Saya baru saja melalui proses ini, dan ada banyak bantuan dan informasi yang sangat baik dalam T / A ini, tetapi saya menemukan saya harus mengumpulkan berbagai elemen (ditambah beberapa dari T / As lain) untuk mendapatkan solusi yang berfungsi dalam untuk berhasil bermigrasi.

Namun, bahkan setelah menggabungkan jawaban yang ada, saya menemukan bahwa skrip Python tidak sepenuhnya berfungsi untuk saya karena tidak berfungsi di mana ada beberapa kejadian boolean di INSERT. Lihat di sini mengapa begitu.

Jadi, saya pikir saya akan memposting jawaban gabungan saya di sini. Penghargaan diberikan kepada mereka yang telah berkontribusi di tempat lain, tentunya. Tetapi saya ingin memberikan sesuatu kembali, dan menghemat waktu orang lain yang mengikuti.

Saya akan memposting skrip di bawah ini. Tapi pertama-tama, inilah instruksi untuk konversi ...

Saya menjalankan skrip pada OS X 10.7.5 Lion. Python bekerja di luar kotak.

Untuk menghasilkan file input MySQL dari database SQLite3 yang ada, jalankan skrip pada file Anda sendiri sebagai berikut,

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

Saya kemudian menyalin file dumped_sql.sql yang dihasilkan ke kotak Linux yang menjalankan Ubuntu 10.04.4 LTS di mana database MySQL saya berada.

Masalah lain yang saya miliki ketika mengimpor file MySQL adalah bahwa beberapa karakter unicode UTF-8 (khususnya tanda kutip tunggal) tidak diimpor dengan benar, jadi saya harus menambahkan saklar ke perintah untuk menentukan UTF-8.

Perintah yang dihasilkan untuk memasukkan data ke dalam database MySQL kosong yang baru adalah sebagai berikut:

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

Biarkan itu dimasak, dan itu sudah seharusnya! Jangan lupa meneliti data Anda, sebelum dan sesudah.

Jadi, seperti yang diminta OP, cepat dan mudah, ketika Anda tahu caranya! :-)

Selain itu, satu hal yang saya tidak yakin sebelum saya melihat ke migrasi ini, adalah apakah nilai field create_at dan updated_at akan dipertahankan - kabar baiknya bagi saya adalah, jadi saya bisa memigrasikan data produksi saya yang ada.

Semoga berhasil!

MEMPERBARUI

Sejak beralih ini, saya telah memperhatikan masalah yang tidak pernah saya perhatikan sebelumnya. Dalam aplikasi Rails saya, bidang teks saya didefinisikan sebagai 'string', dan ini berlanjut ke skema basis data. Proses yang diuraikan di sini menghasilkan ini yang didefinisikan sebagai VARCHAR (255) dalam database MySQL. Ini menempatkan batas 255 karakter pada ukuran bidang ini - dan apa pun di luar ini diam-diam terpotong selama impor. Untuk mendukung panjang teks lebih besar dari 255, skema MySQL perlu menggunakan 'TEXT' daripada VARCHAR (255), saya percaya. Proses yang ditentukan di sini tidak termasuk konversi ini.


Berikut skrip Python yang digabungkan dan direvisi yang berfungsi untuk data saya:

#!/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,
Snips
sumber
1
Terima kasih. Script yang saat ini ditulis di atas memiliki kesalahan sintaksis di dalamnya; "lain:" pada baris 41 tidak pada tingkat indentasi yang tepat. Tidak jelas bagi saya apakah baris di atasnya harus diindentasi atau jika ada sesuatu yang terjadi. Ingin memperbarui?
Dan Tenenbaum
5

Baru-baru ini saya harus bermigrasi dari MySQL ke JavaDB untuk proyek yang sedang dikerjakan oleh tim kami. Saya menemukan perpustakaan Java yang ditulis oleh Apache bernama DdlUtils yang membuatnya sangat mudah. Ini menyediakan API yang memungkinkan Anda melakukan hal berikut:

  1. Temukan skema basis data dan ekspor sebagai file XML.
  2. Ubah DB berdasarkan skema ini.
  3. Mengimpor catatan dari satu DB ke yang lain, dengan asumsi mereka memiliki skema yang sama.

Alat yang kami akhirnya tidak sepenuhnya otomatis, tetapi mereka bekerja dengan cukup baik. Bahkan jika aplikasi Anda tidak di Jawa, seharusnya tidak terlalu sulit untuk menyiapkan beberapa alat kecil untuk melakukan migrasi satu kali. Saya pikir saya dapat menarik migrasi kami dengan kurang dari 150 baris kode.

Programmer Hukum
sumber
4

Tidak perlu skrip, perintah, dll ...

Anda hanya perlu mengekspor database sqlite Anda sebagai .csv file dan kemudian mengimpornya di Mysql menggunakan phpmyadmin.

Saya menggunakannya dan itu bekerja luar biasa ...

NavidIvanian
sumber
Dalam kombinasi dengan ini , ini adalah satu-satunya jawaban yang berhasil untuk saya.
cdauth
3

Berdasarkan solusi Jims: Cara cepat dan mudah untuk memigrasi SQLite3 ke 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  

Ini bekerja untuk saya. Saya menggunakan sed hanya untuk membuang baris pertama, yang tidak seperti mysql, tetapi Anda mungkin juga memodifikasi skrip dump.py untuk membuang baris ini.

alekwisnia
sumber
1
Saya punya beberapa masalah pengkodean UTF-8 dengan data yang diimpor, tetapi menambahkan --default-character-set = utf8 ke perintah impor tampaknya telah memperbaikinya. Diambil dari T / A ini: stackoverflow.com/questions/346092/…
Snips
Oke, saya sudah menambahkan ini - apakah tidak apa-apa?
alekwisnia
Di situlah saya menggunakan saklar ekstra, ya.
Snips
3

Dapatkan dump SQL

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

Impor dump ke MySQL

Untuk impor kecil:

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

atau

mysql -u root -p somedb < myTemporarySQLFile.sql

Ini akan meminta Anda untuk kata sandi. Harap dicatat: Jika Anda ingin memasukkan kata sandi secara langsung, Anda harus melakukannya TANPA spasi, langsung setelah -p:

mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql

Untuk kesedihan yang lebih besar:

mysqlimport atau alat impor lainnya seperti BigDump .

BigDump memberi Anda bilah kemajuan:

masukkan deskripsi gambar di sini

Martin Thoma
sumber
12
Ini tidak berfungsi karena sedikit perbedaan sintaks dan flag pada sqlite vs mysql. Anda masih perlu mengubahnya secara manual.
dlite922
1

Ha ... Kuharap aku menemukan ini dulu! Tanggapan saya terhadap posting ini ... skrip untuk mengkonversi file sql dump sql ke dalam format yang dapat diimpor ke sqlite3 db

Menggabungkan keduanya akan persis seperti yang saya butuhkan:


Ketika database sqlite3 akan digunakan dengan ruby, Anda mungkin ingin mengubah:

tinyint([0-9]*) 

untuk:

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

sayangnya, ini hanya berfungsi karena meskipun Anda memasukkan angka 1 dan 0 ke dalam bidang bertanda boolean, sqlite3 menyimpannya sebagai angka 1 dan 0 sehingga Anda harus melalui dan melakukan sesuatu seperti:

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)

tetapi itu membantu untuk memiliki file sql untuk melihat untuk menemukan semua booleans.

Daicoden
sumber
1

Saya menulis skrip sederhana ini dalam Python3. Ini dapat digunakan sebagai kelas yang disertakan atau skrip mandiri yang dipanggil melalui terminal shell. Secara default mengimpor semua bilangan bulat sebagai int(11)dan string sebagai varchar(300), tetapi semua itu dapat disesuaikan dalam argumen konstruktor atau skrip masing-masing.

CATATAN: Ini membutuhkan Connector MySQL / Python 2.0.4 atau lebih tinggi

Berikut tautan ke sumber di GitHub jika Anda menemukan kode di bawah ini sulit dibaca: 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
sumber
0

Skrip ini ok kecuali untuk kasus ini yang tentu saja, saya sudah bertemu:

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

Script harus memberikan output ini:

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

Tetapi sebaliknya memberikan hasil itu:

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

dengan beberapa karakter non-ascii yang aneh di sekitar 0 dan 1 terakhir.

Ini tidak muncul lagi ketika saya mengomentari baris kode berikut (43-46) tetapi masalah lain muncul:


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

Ini hanya kasus khusus, ketika kami ingin menambahkan nilai menjadi 'f' atau 't' tetapi saya tidak terlalu nyaman dengan ekspresi reguler, saya hanya ingin melihat kasus ini untuk dikoreksi oleh seseorang.

Pokoknya terima kasih banyak untuk skrip yang berguna !!!


sumber
0

Solusi sederhana ini berhasil untuk saya:

<?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
sumber
-5
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql

perhatikan pernyataan BUAT

mgribov
sumber