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

182

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

Теги:
migration

25 ответов

47
Лучший ответ

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

<ч/" > Альтернативный метод, который будет работать хорошо, но редко упоминается: используйте класс ORM, который абстрагирует специфические различия в базе данных для вас. например вы получаете их в PHP (RedBean), Python (слой Django ORM, Storm, SqlAlchemy), Ruby on Rails (ActiveRecord), Cocoa (CoreData)

то есть. вы можете сделать это:

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

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

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

  • НАЧАЛО ОПЕРАЦИИ
  • COMMIT
  • 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' для booleans, MySQL использует 1 и 0 (простое регулярное выражение для этого может завершиться неудачно, когда у вас есть строка вроде: "Я делаю, вы не нажимаете" внутри своего INSERT INTO)
  • SQLLite использует AUTOINCREMENT, MySQL использует AUTO_INCREMENT

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

#! /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;
    }
}
  • 7
    Алекс Мартелли проделал большую работу, переписав это как python на stackoverflow.com/questions/1067060/perl-to-python
  • 0
    Я добавил полный скрипт на python (сам скрипт perl не совсем у меня работал ... требовалась дополнительная обработка для обработки внешних ключей и индексов)
Показать ещё 9 комментариев
39

Вот питон script, построенный из ответа Шалмана и некоторая помощь от Alex martelli в Перевод Perl на Python

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

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

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

Что вы можете импортировать в mysql

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

здесь находится script:

#!/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,
  • 2
    Привет, Джим, в моем наборе данных каждое первое выражение INSERT заключено в обратную кавычку вместо одной кавычки: __ DROP TABLE IF EXISTS schema_migrations; CREATE TABLE, ЕСЛИ НЕ schema_migrations ( version varchar (255) NOT NULL); INSERT INTO schema_migrations VALUES ( 20100714032840 ); INSERT INTO schema_migrations VALUES ('20100714033251'); __
  • 0
    хорошо ... это не отображается выше, но обратные кавычки появляются внутри ЗНАЧЕНИЙ ([HERE] 20100714032840 [/ HERE])
Показать ещё 6 комментариев
23

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

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

Update

В настоящее время поддерживается fork: https://github.com/ludicast/yaml_db

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

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

Преобразует любую форму табличных данных (различные форматы SQL, электронную таблицу Excel) и даже делает диаграммы вашей схемы SQL.

  • 0
    «В настоящее время обрабатываются только части определения SQL (CREATE, ALTER), а не манипуляции с данными (INSERT, UPDATE, DELETE)».
6

Получить дамп 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.

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

Изображение 893

  • 11
    Это не работает из-за небольших различий в синтаксисе и флагов в sqlite против mysql. Вам все еще нужно вручную конвертировать его.
5

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

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

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

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

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

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

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

Пусть он готовит, и это должно быть! Не забудьте внимательно изучить ваши данные до и после.

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

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

Удачи!

ОБНОВЛЕНИЕ

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


Здесь объединенный и переработанный Python script, который работал для моих данных:

#!/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 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,
  • 1
    Благодарю. Сценарий, как написано выше, содержит синтаксическую ошибку; «else:» в строке 41 не соответствует нужному уровню отступа. Мне не ясно, должны ли строки над ним быть с отступом или что-то еще происходит. Хотите обновить?
5

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

sqlite3 sample.db .dump > dump.sql

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

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

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

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

BEGIN TRANSACTION;
...
COMMIT;

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

BEGIN;
...
COMMIT;

Есть и другие подобные проблемы (varchars и двойные кавычки spring), но ничего найти и заменить не удалось.

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

  • 9
    Вы действительно пробовали свое решение?
  • 2
    но самое сложное задание - это разница между грамматиками
5

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

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

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

3

Если вы используете 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')
3

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

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

...

  • 1
    Для тех, кто не знает Python, строки 6-8 выше должны быть вставлены, чтобы соответствовать строкам 3-5
2

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

2

Основываясь на решении Jims: Быстрый простой способ миграции 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, чтобы выбросить эту строку.

  • 1
    У меня были некоторые проблемы с кодировкой UTF-8 с импортированными данными, но добавление --default-character-set = utf8 к команде импорта, похоже, исправило это. Взято из этого Q / A: stackoverflow.com/questions/346092/…
  • 0
    Хорошо, я добавил это - это нормально?
Показать ещё 1 комментарий
2

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

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

1

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

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

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

  • 0
    В сочетании с этим , это единственный ответ, который работал для меня.
1

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

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

Кроме того:

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

Dunn.

  • 1
    Это коммерческое программное обеспечение. Пробная версия доступна, но полная версия стоит $ 149.
1

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

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. Например, строка, содержащая:      , 'Т', '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')
  • 0
    У меня были проблемы с этим исправлением, когда в строке было несколько логических значений. Смотрите мой комбинированный, переработанный скрипт на Python где-нибудь в этой теме для ответа.
1

Ха... Мне жаль, что я не нашел это первым! Мой ответ был на этот пост... script для преобразования sql файла mysql dump в формат, который можно импортировать в sqlite3 db

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


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

tinyint([0-9]*) 

в

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

Увы, эта только половина работает, потому что, хотя вы вставляете 1 и 0 в поле, отмеченное булевым, 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 файл выглядел так, чтобы найти все логические значения.

0

Я взял Python script из https://stackoverflow.com/questions/18671/quick-easy-way-to-migrate-sqlite3-to-mysql (см. выше) и исправил его, чтобы справиться с нашими собственными схемами sqlite. Было несколько проблем, с которыми нужно иметь дело.

Здесь вы можете найти его здесь: https://bitbucket.org/mjogltd/sqlite3mysql

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

0

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

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

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

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

Здесь ссылка на источник на GitHub, если вы находите код ниже, трудно прочитать: https://gist.github.com/techouse/4deb94eee58a02d104c6

#!/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()
  • 0
    ОК :) Отредактировано :)
  • 1
    спасибо за редактирование :-)
0

Это script нормально, за исключением этого случая, что, конечно, я встречал:

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

script должен дать этот результат:

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", но мне не очень нравится регулярные выражения, я просто хотел, чтобы этот случай был исправлен кем-то.

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

-2

Я тщательно проверил все ответы в этом сообщении, а также ответы в другом связанном сообщении Перевод 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. Один для обновленной схемы БД, а другой для обновленных данных БД.

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

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

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

следить за утверждениями CREATE

Ещё вопросы

Сообщество Overcoder
Наверх
Меню