Кто-нибудь знает быстрый простой способ переноса базы данных SQLite3 в MySQL?
Быстрый простой способ миграции SQLite3 в MySQL?
Ответ 1
Вот список конвертеров (не обновляется с 2011 года):
Альтернативный метод, который будет работать хорошо, но редко упоминается: используйте класс ORM, который абстрагирует вас от конкретных различий в базе данных. например Вы получаете их в PHP (RedBean), Python (слой Django ORM, Storm, SqlAlchemy), Ruby on Rails (ActiveRecord) Cocoa (CoreData)
то есть вы могли бы сделать это:
- Загрузка данных из исходной базы данных с использованием класса ORM.
- Храните данные в памяти или сериализуйте на диск.
- Сохраните данные в целевой базе данных, используя класс ORM.
Ответ 2
Кажется, что все начинают с нескольких выражений 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'
для логических значений, MySQL использует1
и0
(простое регулярное выражение для этого может потерпеть неудачу, если у вас есть строка типа "Я делаю, вы не делаете" внутри вашегоINSERT INTO
]) - SQLLite использует
AUTOINCREMENT
, MySQL используетAUTO_INCREMENT
Вот очень простой взломанный скрипт на Perl, который работает для моего набора данных и проверяет многие из этих условий, которые встречаются в других скриптах на Perl, которые я нашел в сети. Мы гарантируем, что это сработает для ваших данных, но вы можете изменить их и опубликовать здесь.
#! /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;
}
}
Ответ 3
Вот питон 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,
Ответ 4
Это беспорядочно, потому что файлы дампа являются специфичными для поставщика баз данных.
Если вы используете Rails, для этого существует отличный плагин. Читайте: http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/
Update
В настоящее время поддерживается fork: https://github.com/ludicast/yaml_db
Ответ 5
MySQL Workbench (лицензия GPL) очень легко мигрирует из SQLite с помощью мастера миграции баз данных. Устанавливается в Windows, Ubuntu, RHEL, Fedora и OS X.
Ответ 6
Вероятно, самый простой способ - использовать команду 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), но ничего найти и заменить не удалось.
Возможно, вы должны спросить, почему вы мигрируете, если проблема с производительностью/базой данных является проблемой, возможно, стоит взглянуть на повторное включение схемы, если система переходит к более мощному продукту, это может быть идеальным временем для планирования будущего вашего данных.
Ответ 7
Удивленный никто не упоминал об этом, но на самом деле для этого явно используется инструмент. Это в perl, SQL: Переводчик: http://sqlfairy.sourceforge.net/
Преобразует любую форму табличных данных (различные форматы SQL, электронную таблицу Excel) и даже делает диаграммы вашей схемы SQL.
Ответ 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
Ответ 9
Я только что прошел этот процесс, и в этом 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,
Ответ 10
Если вы используете 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')
Ответ 11
Мне недавно пришлось перейти от MySQL к JavaDB для проекта, над которым работает наша команда. Я нашел Java-библиотеку, написанную Apache под названием DdlUtils, которая сделала это довольно легко. Он предоставляет API, который позволяет выполнять следующие действия:
- Откройте схему базы данных и экспортируйте ее в виде XML файла.
- Измените базу данных на основе этой схемы.
- Импортировать записи из одной базы данных в другую, предполагая, что они имеют одну и ту же схему.
Инструменты, которые мы закончили, не были полностью автоматизированы, но они работали очень хорошо. Даже если ваше приложение не находится на Java, не должно быть слишком сложно взломать несколько небольших инструментов для одноразовой миграции. Я думаю, что смог преодолеть миграцию с менее чем 150 строк кода.
Ответ 12
Я обычно использую функцию экспорта/импорта таблиц feature of IntelliJ DataGrip.
Вы можете увидеть прогресс в правом нижнем углу.
[]
Ответ 13
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('"', "'")
...
Ответ 14
Основываясь на решении 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, чтобы выбросить эту строку.
Ответ 15
Получить дамп SQL
[email protected]$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql
Импортировать дамп в MySQL
Для небольшого импорта:
[email protected]$ 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 дает вам индикатор выполнения:
Ответ 16
Нет необходимости в каких-либо script, командах и т.д.
вам нужно экспортировать только базу данных sqlite в качестве файла .csv
, а затем импортировать ее в Mysql с помощью phpmyadmin.
Я использовал его, и он работал потрясающе...
Ответ 17
Я использую загрузчик данных для переноса практически любых данных, это помогает мне преобразовать MSSQL в MYSQL, доступ к MS для MSSQL, mysql, csv loader, foxpro и MSSQL для доступа к MS, MYSQl, CSV, foxpro и т.д. На мой взгляд, это лучший инструмент переноса данных
Скачать бесплатно: http://www.dbload.com
Ответ 18
Ха... Мне жаль, что я не нашел это первым! Мой ответ был на этот пост... 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 файл выглядел так, чтобы найти все логические значения.
Ответ 19
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')
Ответ 20
это программное обеспечение из коробки - работает для меня. попробуйте и сообщите другим.
https://dbconvert.com/sqlite/mysql/
Кроме того:
Мне пришлось сделать одно небольшое изменение: каким-то образом auto_increment одного поля (поле, найденное из сообщения об ошибке) не было включено. Итак, в phpmyadmin я проверяю свойство A_I этого поля, и он работает полностью. Надеюсь, что это поможет.
Dunn.
Ответ 21
Я написал этот простой скрипт на Python3. Он может использоваться как включенный класс или автономный скрипт, вызываемый через терминальную оболочку. По умолчанию он импортирует все целые числа как int(11)
и строки как varchar(300)
, но все это можно изменить в аргументах конструктора или скрипта соответственно.
ПРИМЕЧАНИЕ: Требуется MySQL, Connector/Python 2.0.4 или выше
Вот ссылка на источник на GitHub, если вам трудно прочитать приведенный ниже код: 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()
Ответ 22
Это 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!!!
Ответ 23
Это простое решение для меня:
<?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 ) );
}
}
Ответ 24
Я взял Python script из fooobar.com/questions/34695/... (см. выше) и исправил его, чтобы справиться с нашими собственными схемами sqlite. Было несколько проблем, с которыми нужно иметь дело.
Здесь вы можете найти его здесь: https://bitbucket.org/mjogltd/sqlite3mysql
Также доступно то же самое, что и изображение Docker, здесь: https://hub.docker.com/r/mjog/sqlite3mysql/ - он полностью доступен даже под рабочим столом Windows.
Ответ 25
Я тщательно проверил все ответы в этом сообщении, а также ответы в другом связанном сообщении Перевод 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 с помощью любого текстового редактора, не беспокоясь об изменении содержимого.
Надеюсь, что это может помочь другим в будущем.
Ответ 26
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql
следить за утверждениями CREATE