Быстрый и простой способ перенести SQLite3 в MySQL?

StackOverflow https://stackoverflow.com/questions/18671

  •  09-06-2019
  •  | 
  •  

Вопрос

Кто-нибудь знает быстрый и простой способ перенести базу данных SQLite3 в MySQL?

Это было полезно?

Решение

Вот список конвертеров (не обновлялся с 2011 года):


Альтернативный метод, который хорошо бы работал, но редко упоминается, - это:используйте класс ORM, который абстрагирует для вас конкретные различия в базе данных.например ,вы получаете это в PHP (Рыжебородый), Python (уровень ORM Django, Шторм, SQL - алхимия), Ruby on Rails (Рубин на рельсах) (Активная запись), Какао (Основные данные)

т. е.ты мог бы это сделать:

  1. Загрузите данные из исходной базы данных, используя класс ORM.
  2. Храните данные в памяти или сериализуйте на диск.
  3. Храните данные в целевой базе данных, используя класс ORM.

Другие советы

Кажется, все начинают с нескольких выражений greps и perl, и вы вроде как получаете что-то, что работает для вашего конкретного набора данных, но вы понятия не имеете, правильно ли импортированы данные или нет.Я серьезно удивлен, что никто не создал надежную библиотеку, которая могла бы конвертировать между ними.

Вот список ВСЕХ различий в синтаксисе SQL, о которых я знаю, между двумя форматами файлов:Строки , начинающиеся с:

  • НАЧАТЬ ТРАНЗАКЦИЮ
  • ЗАФИКСИРОВАТЬ
  • последовательность sqlite_sequence
  • СОЗДАТЬ УНИКАЛЬНЫЙ ИНДЕКС

не используются в MySQL

  • Использование SQLLite CREATE TABLE/INSERT INTO "table_name" и MySQL использует CREATE TABLE/INSERT INTO table_name
  • MySQL не использует кавычки внутри определения схемы
  • MySQL использует одинарные кавычки для строк внутри INSERT INTO пункты
  • SQLLite и MySQL имеют разные способы экранирования строк внутри INSERT INTO пункты
  • Использование SQLLite 't' и 'f' для логических значений MySQL использует 1 и 0 (простое регулярное выражение для этого может привести к сбою, если у вас есть строка типа:"Я знаю, ты не находишься внутри своего INSERT INTO)
  • Использование SQLLite AUTOINCREMENT, MySQL использует AUTO_INCREMENT

Вот очень простой взломанный perl-скрипт, который работает для мой dataset и проверяет на многие другие из этих условий другие скрипты perl, которые я нашел в Интернете.Nu гарантирует, что это будет работать с вашими данными, но не стесняйтесь вносить изменения и публиковать их здесь.

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

Вот скрипт на Python, созданный на основе ответа Шалманезе и некоторой помощи от Алекса Мартелли по адресу Перевод Perl на Python

Я делаю это вики-сайтом сообщества, поэтому, пожалуйста, не стесняйтесь редактировать и рефакторинговать, если это не нарушает функциональность (к счастью, мы можем просто откатить) - это довольно некрасиво, но работает

используйте примерно так (при условии, что скрипт вызван dump_for_mysql.py:

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

Который затем вы можете импортировать в mysql

примечание - вам нужно добавить ограничения внешнего ключа вручную, поскольку sqlite фактически их не поддерживает

вот сценарий:

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

Это грязно, потому что файлы дампа зависят от поставщика базы данных.

Если вы используете Rails, для этого существует отличный плагин.Читать: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/

Обновить

Поддерживаемая в настоящее время вилка: https://github.com/ludicast/yaml_db

MySQL Workbench (лицензия GPL) очень легко переносится с SQLite с помощью Мастер миграции базы данных.Устанавливается на Windows, Ubuntu, RHEL, Fedora и OS X.

Удивлен, что никто до сих пор не упомянул об этом, но на самом деле для этого есть инструмент.Это на perl, SQL:Переводчик:http://sqlfairy.sourceforge.net/

Преобразует практически любые формы табличных данных (различные форматы SQL, электронные таблицы Excel) и даже создает диаграммы вашей схемы 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

Я только что прошел через этот процесс, и в этом Q / A есть много очень хорошей помощи и информации, но я обнаружил, что мне пришлось объединить различные элементы (плюс некоторые из других Q / As), чтобы получить рабочее решение для успешной миграции.

Однако даже после объединения существующих ответов я обнаружил, что скрипт Python не полностью работал для меня, поскольку он не работал там, где во ВСТАВКЕ было несколько логических вхождений.Видишь здесь почему это было так.

Итак, я решил опубликовать свой объединенный ответ здесь.Заслуга, конечно, принадлежит тем, кто внес свой вклад в других местах.Но я хотел отдать что-то взамен и сэкономить время других людей, которые последуют за мной.

Я опубликую сценарий ниже.Но, во-первых, вот инструкции по преобразованию...

Я запустил скрипт на OS X 10.7.5 Lion.Python работал "из коробки".

Чтобы сгенерировать входной файл MySQL из вашей существующей базы данных SQLite3, запустите скрипт для ваших собственных файлов следующим образом,

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

Затем я скопировал полученный файл dumped_sql.sql в окно Linux под управлением Ubuntu 10.04.4 LTS, где должна была находиться моя база данных MySQL.

Другая проблема, с которой я столкнулся при импорте файла MySQL, заключалась в том, что некоторые символы unicode UTF-8 (в частности, одинарные кавычки) импортировались некорректно, поэтому мне пришлось добавить переключатель в команду для указания UTF-8.

Результирующая команда для ввода данных в новую пустую базу данных MySQL выглядит следующим образом:

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

Дайте ему приготовиться, и на этом все должно закончиться!Не забудьте внимательно изучить свои данные до и после.

Итак, как и просила операционная система, это быстро и легко, если вы знаете, как это сделать!:-)

Кроме того, одна вещь, в которой я не был уверен до того, как изучил эту миграцию, заключалась в том, будут ли сохранены значения полей created_at и updated_at - хорошей новостью для меня является то, что это так, поэтому я мог перенести свои существующие производственные данные.

Удачи вам!

Обновить

После этого переключения я заметил проблему, которой раньше не замечал.В моем приложении Rails мои текстовые поля определяются как "строка", и это переносится в схему базы данных.Описанный здесь процесс приводит к тому, что они определяются как VARCHAR(255) в базе данных MySQL.Это накладывает ограничение в 255 символов на размеры этих полей - и все, что выходит за рамки этого, было автоматически усечено во время импорта.Я полагаю, что для поддержки длины текста, превышающей 255, схеме MySQL необходимо было бы использовать 'TEXT', а не VARCHAR(255).Процесс, определенный здесь, не включает в себя это преобразование.


Вот объединенный и переработанный скрипт Python, который работал с моими данными:

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

Вероятно, самый быстрый и простой способ - это использовать команду sqlite .dump, в данном случае создать дамп образца базы данных.

sqlite3 sample.db .dump > dump.sql

Затем вы можете (теоретически) импортировать это в базу данных mysql, в данном случае в тестовую базу данных на сервере баз данных 127.0.0.1, используя пользователя root.

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

Я говорю теоретически, поскольку между грамматиками есть несколько различий.

В sqlite начинаются транзакции

BEGIN TRANSACTION;
...
COMMIT;

MySQL использует только

BEGIN;
...
COMMIT;

Есть и другие подобные проблемы (на ум приходят переменные и двойные кавычки), но ничего из того, что find and replace не смог исправить.

Возможно, вам следует спросить, почему вы выполняете миграцию, если проблема заключается в производительности / размере базы данных, возможно, посмотрите на повторную настройку схемы, если система переходит на более мощный продукт, это может быть идеальным временем для планирования будущего ваших данных.

Если вы используете Python / Django, это довольно просто:

создайте две базы данных в settings.py (как здесь https://docs.djangoproject.com/en/1.11/topics/db/multi-db/)

тогда просто сделай вот так:

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

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

Недавно мне пришлось перейти с MySQL на JavaDB для проекта, над которым работает наша команда.Я нашел Библиотека Java, написанная Apache, называется DdlUtils это сделало задачу довольно простой.Он предоставляет API, который позволяет вам выполнять следующее:

  1. Найдите схему базы данных и экспортируйте ее в виде XML-файла.
  2. Измените базу данных на основе этой схемы.
  3. Импортируйте записи из одной базы данных в другую, предполагая, что они имеют одну и ту же схему.

Инструменты, с которыми мы в итоге столкнулись, не были полностью автоматизированы, но работали довольно хорошо.Даже если ваше приложение не на Java, создать несколько небольших инструментов для одноразовой миграции не должно быть слишком сложно.Я думаю, что мне удалось завершить нашу миграцию, используя менее 150 строк кода.

Получаем SQL-дамп

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

Импортировать дамп в MySQL

Для небольшого импорта:

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

или

mysql -u root -p somedb < myTemporarySQLFile.sql

При этом вам будет предложено ввести пароль.Пожалуйста, обратите внимание:Если вы хотите ввести свой пароль напрямую, вы должны сделать это БЕЗ пробела, непосредственно после -p:

mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql

Для больших свалок:

mysqlimport или другие инструменты импорта, такие как Большая свалка.

BigDump выдает вам индикатор выполнения:

enter image description here

Скрипт на Python работал после нескольких изменений следующим образом:

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

...

Нет необходимости в каком-либо скрипте, команде и т.д...

вам нужно экспортировать свою базу данных sqlite только в виде .csv файл, а затем импортируйте его в Mysql с помощью phpmyadmin.

Я использовал его, и это сработало потрясающе...

Я использую data Loader для переноса практически любых данных, это помогает мне конвертировать MSSQL в MYSQL, MS access в MSSQL, mysql, csv loader, foxpro и MSSQL в MS access, MySQL, CSV, foxpro и т.д.На мой взгляд, это лучший инструмент переноса данных

Скачать Бесплатно : http://www.dbload.com

Основано на решении Джимса:Быстрый и простой способ перенести SQLite3 в 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  

У меня это работает.Я использую sed только для того, чтобы выбросить первую строку, которая не похожа на mysql, но вы также можете изменить dump.py script, чтобы выбросить эту строку.

Ha...Жаль, что я не нашел это первым!Мой ответ был на этот пост... скрипт для преобразования SQL-файла дампа mysql в формат, который может быть импортирован в базу данных sqlite3

Объединение этих двух было бы именно тем, что мне было нужно:


Когда база данных sqlite3 будет использоваться с ruby, вы можете захотеть изменить:

tinyint([0-9]*) 

Для:

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

увы, это работает только наполовину, потому что, хотя вы вставляете 1 и 0 в поле с пометкой boolean, sqlite3 сохраняет их как 1 и 0, поэтому вам нужно пройти и сделать что-то вроде:

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)

но было полезно просмотреть sql-файл, чтобы найти все логические значения.

фаллино правильно определил местоположение ошибки в скрипте.У меня есть решение.Проблема заключается в следующих строках:

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

Шаблон замены (2-й параметр) в вызовах re.sub является "обычной" строкой, поэтому вместо \1, расширяющегося до первого соответствия регулярному выражению, он расширяется до литерала 0x01.Аналогично, \2 расширяется до 0x02.Например, строка, содержащая:, 't', 'f', были бы заменены на:<0x01>10<0x02>
(Первая замена изменяет 't' на <0x1>1<0x2> Вторая замена изменяется <0x02>'f', к <0x1>0<0x1>)

Исправление заключается либо в изменении строк замены путем добавления префикса 'r', либо путем экранирования \1 и \2 в существующей строке.Поскольку простое манипулирование строками регулярных выражений - это то, для чего предназначены необработанные строки, вот исправление с их использованием:

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

это программное обеспечение из коробки - работает у меня.попробуйте это и дайте знать другим.

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

Кроме того,:

Мне пришлось внести одно небольшое изменение:каким-то образом авто_инкремент одного поля (поля, найденного из сообщения об ошибке) не был включен.Итак, в phpmyadmin я проверяю свойство A_I этого поля, и оно работает полностью.Надеюсь, это поможет.

Данн.

Я написал этот простой скрипт на Python3.Он может использоваться как включенный класс или отдельный скрипт, вызываемый через оболочку терминала.По умолчанию он импортирует все целые числа как int(11)и строки в виде varchar(300), но все это можно настроить в аргументах конструктора или скрипта соответственно.

ПРИМЕЧАНИЕ: Для этого требуется MySQL Connector / Python 2.0.4 или выше

Вот ссылка на исходный код на GitHub, если вам трудно прочитать приведенный ниже код: 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()

Обычно я использую Экспорт / импорт таблиц особенность IntelliJ DataGrip.

step 1 step 2 step 3

Вы можете увидеть прогресс в правом нижнем углу.

[enter image description here]

Этот сценарий в порядке, за исключением этого случая, с которым я, конечно, встречался :

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

Скрипт должен выдавать этот результат :

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

Но дает вместо этого такой результат :

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

с какими-то странными символами, отличными от ascii, вокруг последних 0 и 1.

Это больше не появлялось, когда я комментировал следующие строки кода (43-46), но появились другие проблемы:


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

Это просто особый случай, когда мы хотим добавить значение 'f' или 't', но мне не очень нравятся регулярные выражения, я просто хотел указать на этот случай, чтобы кто-нибудь исправил его.

В любом случае, большое спасибо за этот удобный скрипт!!!

Это простое решение сработало для меня:

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

Я взял скрипт Python из https://stackoverflow.com/a/32243979/746459 (выше) и исправили это, чтобы справляться с нашими собственными схемами sqlite.Предстояло решить несколько проблем.

Вы можете найти это в системе управления версиями здесь: https://bitbucket.org/mjogltd/sqlite3mysql

Также доступно то же самое, что и изображение Docker, здесь: https://hub.docker.com/r/mjog/sqlite3mysql/ - он полностью пригоден для использования даже на рабочем столе Windows.

Я тщательно проверил все ответы в этом посте, а также ответы в другом соответствующем посте Перевод Perl на Python.И все же ни один из них не смог полностью решить мою проблему.

Мой сценарий заключается в том, что мне нужно перенести базу данных Trac из sqlite в MySQL, и база данных содержит много технологического вики-контента.Поэтому внутри INSERT INTO значения, там могут быть SQL-инструкции типа CREATE TABLE и AUTOINCREMENT.Но при построчной замене там могут быть неправильные замены.

В конце концов я написал свой собственный инструмент для этой цели:

https://github.com/motherapp/sqlite_sql_parser

Использование относительно простое:

python parse_sqlite_sql.py export.sql

Будут сгенерированы два файла: export.sql.schema.sql и export.sql.data.sql.Один для обновленной схемы БД, а другой для обновленных данных БД.

Можно было бы внести дополнительные изменения вручную в файл схемы базы данных, используя любой текстовый редактор, не беспокоясь об изменении содержимого.

Надеюсь, это поможет другим в будущем.

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

следите за инструкциями CREATE

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top