有人知道一个快速简单的方法来迁移SQLite3数据库到MySQL吗?
当前回答
最近,为了我们团队正在进行的一个项目,我不得不从MySQL迁移到JavaDB。我发现Apache编写的一个名为DdlUtils的Java库非常容易做到这一点。它提供了一个API,让你做以下事情:
发现数据库的模式并将其导出为XML文件。 根据此模式修改DB。 将记录从一个DB导入到另一个DB,假设它们具有相同的模式。
我们最终使用的工具并不是完全自动化的,但它们工作得很好。即使您的应用程序不是用Java编写的,使用一些小工具进行一次性迁移也不会太难。我认为我只用了不到150行代码就完成了迁移。
其他回答
这个简单的解决方案对我很有效:
<?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 ) );
}
}
我刚刚经历了这个过程,在这个Q/ a中有很多非常好的帮助和信息,但我发现我必须将各种元素(加上来自其他Q/ a的一些元素)组合在一起,以获得一个有效的解决方案,以便成功迁移。
然而,即使在结合现有的答案后,我发现Python脚本并没有完全为我工作,因为它在INSERT中出现多个布尔值时不起作用。看看为什么会这样。
所以,我想把我合并后的答案贴在这里。当然,功劳归于那些在其他地方做出贡献的人。但我想回馈一些东西,并节省其他人随后的时间。
我将在下面发布脚本。但首先,这里是转换的说明…
我在OS X 10.7.5 Lion上运行该脚本。巨蟒开箱即用。
要从您现有的SQLite3数据库生成MySQL输入文件,在您自己的文件上运行脚本,如下所示:
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。
将数据输入一个新的空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字段值是否会被保留——对我来说,好消息是它们会被保留,所以我可以迁移现有的生产数据。
好运!
更新
Since making this switch, I've noticed a problem that I hadn't noticed before. In my Rails application, my text fields are defined as 'string', and this carries through to the database schema. The process outlined here results in these being defined as VARCHAR(255) in the MySQL database. This places a 255 character limit on these field sizes - and anything beyond this was silently truncated during the import. To support text length greater than 255, the MySQL schema would need to use 'TEXT' rather than VARCHAR(255), I believe. The process defined here does not include this conversion.
以下是对我的数据进行合并和修改后的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,
最近,为了我们团队正在进行的一个项目,我不得不从MySQL迁移到JavaDB。我发现Apache编写的一个名为DdlUtils的Java库非常容易做到这一点。它提供了一个API,让你做以下事情:
发现数据库的模式并将其导出为XML文件。 根据此模式修改DB。 将记录从一个DB导入到另一个DB,假设它们具有相同的模式。
我们最终使用的工具并不是完全自动化的,但它们工作得很好。即使您的应用程序不是用Java编写的,使用一些小工具进行一次性迁移也不会太难。我认为我只用了不到150行代码就完成了迁移。
最简单的方法可能是使用sqlite .dump命令,在本例中创建示例数据库的转储。
sqlite3 sample.db .dump > dump.sql
然后(理论上)您可以使用root用户将其导入到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和双引号会回到脑海中),但没有查找和替换不能解决的问题。
也许你应该问问为什么要迁移,如果性能/数据库大小是问题,也许应该考虑重新规划模式,如果系统正在迁移到更强大的产品,这可能是计划数据未来的理想时机。
echo ".dump" | sqlite3 /tmp/db.sqlite > db.sql
注意CREATE语句
推荐文章
- 重复键忽略?
- 将表从一个数据库复制到另一个数据库的最简单方法?
- 如何通过查询在MySQL中获得数据库结构?
- MySQL删除表中的所有行,并将ID重置为零
- 在准备语句中使用“like”通配符
- MySQL中的表名是否区分大小写?
- 库未加载:libmysqlclient.16。在OS X 10.6上使用mysql2 gem运行'rails server'时出现dylib错误
- 如何知道MySQL表最近一次更新?
- 如何转储一些SQLite3表的数据?
- 在MySQL中的一个查询中更新多个具有不同值的行
- 如果表存在则删除表并创建它,如果不存在则创建它
- MySQL OR与IN性能
- 将值从同一表中的一列复制到另一列
- 删除id与其他表不匹配的sql行
- MySQL CPU使用率高