快速简单的方法将SQLite3迁移到MySQL?
任何人都知道一个简单的方法将SQLite3数据库迁移到MySQL?
这是一个转换器列表(2011年以来没有更新):
- http://www.sqlite.org/cvstrac/wiki?p=ConverterTools (或archive.org上的快照 )
可以很好地工作,但很less提及的另一种方法是:使用一个ORM类,为您抽象出特定的数据库差异。 例如你在PHP( RedBean ),Python(Django的ORM层, Storm , SqlAlchemy ),Ruby on Rails( ActiveRecord ),Cocoa( CoreData )
即你可以这样做:
- 使用ORM类从源数据库加载数据。
- 将数据存储在内存中或序列化到磁盘。
- 使用ORM类将数据存储到目标数据库中。
每个人似乎都开始了几个greps和perlexpression式,而且你还可以得到适合你的特定数据集的东西,但是你不知道它是否正确导入了数据。 我真的很惊讶没有人build立了一个坚实的库,可以在两者之间进行转换。
这里列出了我所了解的两种文件格式之间的所有SQL语法差异:
- BEGIN TRANSACTION
- 承诺
- sqlite_sequence
- 创build唯一索引
没有在MySQL中使用
- SQLlite使用CREATE TABLE / INSERT INTO“table_name”,MySQL使用CREATE TABLE / INSERT INTO table_name
- MySQL不在模式定义中使用引号
- MySQL在INSERT INTO子句中使用单引号
- SQLlite和MySQL在INSERT INTO子句中有不同的转义string的方法
- SQLlite使用“t”和“f”作为布尔值,MySQL使用1和0(当你有一个像这样的string时,一个简单的正则expression式可能会失败:'我不知道你的INSERT INTO'
- SQLLite使用AUTOINCREMENT,MySQL使用AUTO_INCREMENT
这是一个非常基本的黑客perl脚本,它适用于我的数据集,并检查更多的这些条件,我在网上find的其他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; } }
这里是一个python脚本,由Shalmanese的答案和Alex martelli 翻译Perl到Python的一些帮助
我使它成为社区wiki,所以请随意编辑,并重构,只要它不打破function(幸好我们可以回滚) – 这是相当丑陋的,但工程
像这样使用(假设脚本被称为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
到目前为止还没有人提到这个,但实际上有一个明确的工具。 这是在Perl中,SQL:翻译: http : //sqlfairy.sourceforge.net/
大多数任何forms的表格数据(不同的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
我最近不得不从MySQL迁移到JavaDB,以开发我们团队正在开发的项目。 我发现了一个由Apache编写的叫做DdlUtils的Java库 ,它使得这很容易。 它提供了一个API,可以让你做到以下几点:
- 发现数据库的模式并将其导出为XML文件。
- 根据此模式修改数据库。
- 从一个数据库导入logging到另一个数据库,假设它们具有相同的模式。
我们结束的工具不是完全自动化的,但是工作得很好。 即使您的应用程序不在Java中,也不应该太难以掀起一些小工具来进行一次性迁移。 我认为我能够通过less于150行的代码来实现我们的迁移。
可能最简单的方法是使用sqlite .dump命令,在这种情况下创build示例数据库的转储。
sqlite3 sample.db .dump > dump.sql
然后你可以(理论上)将这个数据导入到mysql数据库中,在这种情况下,数据库服务器127.0.0.1上的testing数据库使用root用户。
mysql -p -u root -h 127.0.0.1 test < dump.sql
我在理论上说,语法之间有一些差异。
在sqlite交易开始
BEGIN TRANSACTION; ... COMMIT;
MySQL只使用
BEGIN; ... COMMIT;
还有其他类似的问题(varchars和双引号回想起来),但没有发现和replace无法修复。
也许你应该问为什么你要迁移,如果性能/数据库的大小是问题,也许看看重新架构模式,如果系统正在转移到一个更强大的产品,这可能是计划未来数据的理想时间。
获取一个SQL转储
moose@pc08$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql
导入转储到MySQL
对于小型import:
moose@pc08$ mysql -u <username> -p Enter password: .... mysql> use somedb; Database changed mysql> source myTemporarySQLFile.sql;
要么
mysql -u root -p somedb < myTemporarySQLFile.sql
这会提示你input密码。 请注意:如果你想直接input你的密码,你必须在没有空格的情况下直接input-p
:
mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql
对于较大的转储:
mysqlimport或其他像BigDump这样的导入工具。
BigDump给你一个进度条:
我刚刚经历了这个过程,在这个Q / A中有很多非常好的帮助和信息,但是我发现我必须将各种元素(加上其他Q / A中的一些)汇集到一起以获得工作解决scheme为了成功迁移。
但是,即使在结合现有的答案之后,我发现Python脚本并没有完全适用于我,因为它在INSERT中有多个布尔值时不起作用。 看到这里为什么是这样的情况。
所以,我想我会在这里发布我的合并答案。 信用是那些当然在别处有贡献的人。 但是我想回馈一些东西,并节省时间。
我将在下面发布脚本。 但首先,这是转换的说明…
我在OS X 10.7.5 Lion上运行脚本。 Python开箱即用。
要从现有的SQLite3数据库生成MySQLinput文件,请按照以下步骤在自己的文件上运行脚本,
Snips$ sqlite3 original_database.sqlite3 .dump | python ~/scripts/dump_for_mysql.py > dumped_data.sql
然后我把结果dumped_sql.sql文件复制到运行Ubuntu 10.04.4 LTS的Linux机器上,在这里我的MySQL数据库将驻留在那里。
导入MySQL文件时遇到的另一个问题是某些unicode UTF-8字符(特别是单引号)没有被正确导入,所以我不得不在命令中添加一个开关来指定UTF-8。
input数据到一个新的空的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字段值保留 – 对我来说是个好消息,所以我可以迁移我现有的生产数据。
祝你好运!
UPDATE
自从做这个开关以来,我注意到了一个我以前没有注意到的问题。 在我的Rails应用程序中,我的文本字段被定义为“string”,并传递给数据库模式。 这里概述的过程导致这些在MySQL数据库中被定义为VARCHAR(255)。 这会在这些字段大小上放置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,
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 AZ 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('"', "'")
…
如果您使用的是Python / Django,那么这非常简单:
在settings.py中创build两个数据库(如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')
我使用数据加载器来迁移几乎所有的数据,这有助于我将MSSQL转换为MYSQL,MS访问MSSQL,mysql,csv loader,foxpro和MSSQL到MS访问,MYSQl,CSV,foxpro等。在我看来,这是一个最好的数据迁移工具
免费下载: http : //www.dbload.com
基于吉姆的解决scheme: 快速简单的方法将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脚本来抛出这一行。
MySQL Workbench(GPL许可证)通过数据库迁移向导非常容易地从SQLite 迁移 。 安装在Windows,Ubuntu,RHEL,Fedora和OS X上 。
哈…我希望我已经find了第一! 我的回应是这个post… 脚本将mysql转储sql文件转换成可以导入到sqlite3数据库的格式
结合这两个将是我所需要的:
当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文件来查找所有布尔值是有帮助的。
fallino在脚本中正确识别错误的位置。 我有解决scheme。 问题是以下几行:
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')
re.sub调用中的replace模式(第2个参数)是一个“常规”string,所以扩展为第一个正则expression式匹配,而不是扩展为文字0x01。 同样,\ 2展开为0x02。 例如,包含:,'t','f'的行将被replace为:<0x01> 10 <0x02>
(第一个replace变为't',变为<0x1> 1 <0x2>第二个replace变为<0x02>'f',至<0x1> 0 <0x1>)
解决方法是通过添加“r”前缀或通过在现有string中转义\ 1和\ 2来更改replacestring。 由于简单的正则expression式string的操作是原始string的用途,下面是使用这些修复程序的修复:
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/
此外:
我不得不做一个小的改变:不知何故auto_increment一个字段(从错误消息find的字段)未启用。 所以在phpmyadmin我检查这个领域的属性A_I,它完全工作。 希望能帮助到你。
邓恩。
不需要任何脚本,命令等
你只需要将你的sqlite数据库导出为.csv
文件,然后使用phpmyadmin将它导入到Mysql中。
我用它,它的工作令人惊叹…
这个脚本是好的,除了这个情况,当然,我遇到了:
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;
在最后的0和1周围有一些奇怪的非ASCII字符。
当我评论下面的代码(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'的值,但是我对正则expression式并不是很熟悉的时候,我只是想要发现这个情况被某个人纠正。
无论如何,非常感谢那个方便的脚本!
我在Python3中编写了这个简单的脚本。 它可以用作通过terminalshell调用的包含类或独立脚本。 默认情况下,它将所有整数作为int(11)
和string作为varchar(300)
导入,但是可以分别在构造函数或脚本参数中进行调整。
注:它需要MySQL Connector / Python 2.0.4或更高版本
这里有一个链接到GitHub上的源代码,如果你发现下面的代码难以阅读: https : //gist.github.com/techouse/4deb94eee58a02d104c6
#!/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()
这个简单的解决scheme为我工作:
<?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 ) ); } }
我已经采取从https://stackoverflow.com/a/32243979/746459 (上面)的Python脚本,并修复它以应付我们自己的sqlite模式。 有几个问题需要处理。
你可以在这里find源代码控制: https : //bitbucket.org/mjogltd/sqlite3mysql
也可以使用与Docker镜像相同的东西,在这里: https : //hub.docker.com/r/mjog/sqlite3mysql/ – 即使在Windows桌面下也是完全可用的。
我仔细检查了这篇文章中的所有答案,以及另一篇相关的文章将Perl翻译成Python 。 然而没有人能完全解决我的问题。
我的scheme是我需要将Trac的数据库从sqlite迁移到MySQL,并且数据库包含大量基于技术的wiki内容。 因此,在INSERT INTO
值中,可能会有像CREATE TABLE
和AUTOINCREMENT
这样的SQL语句。 但是逐行replace在那里可能有错误的replace。
最终我为此写了自己的工具:
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语句