当前位置:  开发笔记 > 编程语言 > 正文

将SQLite3迁移到MySQL的快速简便方法?

如何解决《将SQLite3迁移到MySQL的快速简便方法?》经验,为你挑选了11个好方法。

有人知道将SQLite3数据库迁移到MySQL的快捷方法吗?



1> Shalmanese..:

每个人似乎从一些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使用10(当你有一个字符串时,一个简单的正则表达式可能会失败:'我做,你不在你的内部INSERT INTO)

SQLLite使用AUTOINCREMENT,MySQL使用AUTO_INCREMENT

这是一个非常基本的被破解的perl脚本,它适用于我的数据集,并检查我在网上找到的其他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;
    }
}


Alex martelli在http://stackoverflow.com/questions/1067060/perl-to-python上重写了这个python
我理解你的脚本是"快速和脏",但也非常有用,所以这里有一些补充/错误修正:*在`&&($ line!〜/ CREATE UNIQUE INDEX /)`添加`&&($ line!〜/ PRAGMA)之后foreign_keys = OFF /)`*table-name-matching regex错过了数字,而不是`$ line =〜/ INSERT INTO \"([a-z _]*)\"(.*)/`必须有`$ line =〜/ INSERT INTO \"([a-z_1-9]*)\"(.*)/`希望这有助于未来的读者
ANSI模式下的MySQL接受双引号中的标识符.
[COMMIT](http://dev.mysql.com/doc/refman/5.0/en/commit.html)和[CREATE UNIQUE INDEX](http://dev.mysql.com/doc/refman/5.0/en /create-index.html)是有效的MySQL命令,请修复它.

2> David d C e ..:

以下是转换器列表(自2011年以来未更新):

http://www.sqlite.org/cvstrac/wiki?p=ConverterTools(或archive.org上的快照)


一种可以很好地工作但很少提及的另一种方法是:使用一个ORM类来为您提取特定的数据库差异.例如,你在PHP(RedBean),Python(Django的ORM层,Storm,SqlAlchemy),Ruby on Rails(ActiveRecord),Cocoa(CoreData)中获得这些

即你可以这样做:

    使用ORM类从源数据库加载数据.

    将数据存储在内存中或序列化到磁盘.

    使用ORM类将数据存储到目标数据库中.



3> Jiaaro..:

这是一个python脚本,基于Shalmanese的答案和Alex martelli在翻译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,


嗨Jim,在我的数据集中,每个第一个INSERT语句都被反引号而不是单引号包装:__ DROP TABLE IF EXISTS schema_migrations; CREATE TABLE IF NOT NOT EXISTS`schema_migrations`(`version` varchar(255)NOT NULL); INSERT INTO schema_migrations VALUES(`20100714032840`); INSERT INTO schema_migrations VALUES('20100714033251'); __

4> ryw..:

它很混乱,因为转储文件是特定于数据库供应商的.

如果您正在使用Rails,那么就存在一个很棒的插件.阅读:http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/

更新

目前维护的fork:https://github.com/ludicast/yaml_db



5> Patrick Garn..:

MySQL Workbench(GPL许可证)通过数据库迁移向导非常容易地从SQLite 迁移.安装在Windows,Ubuntu,RHEL,Fedora和OS X上.



6> Richard Gour..:

可能最简单的方法是使用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和双引号重新出现),但没有找到和替换无法修复.

也许您应该问为什么要迁移,如果性能/数据库大小是问题,或许可以看看重新构建模式,如果系统转向更强大的产品,这可能是计划数据未来的理想时间.


但最困难的任务是文法之间的差异

7> pdxleif..:

令人惊讶的是,现在还没有人提到这一点,但实际上有一个明确的工具.它在perl,SQL:翻译:http: //sqlfairy.sourceforge.net/

在大多数任何形式的表格数据(不同的SQL格式,Excel电子表格)之间进行转换,甚至可以制作SQL模式的图表.



8> Dashamir Hox..:

http://sqlfairy.sourceforge.net/

http://search.cpan.org/dist/SQL-Translator/

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> 小智..:

如果您使用的是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')



10> Snips..:

我刚刚完成了这个过程,在这个Q/A中有很多非常好的帮助和信息,但我发现我必须将各种元素(加上其他Q/As中的一些元素)整合在一起以获得一个可行的解决方案为了成功迁移.

然而,即使在结合现有答案之后,我发现Python脚本对我来说并不完全有用,因为它在INSERT中存在多个布尔出现的情况下不起作用.看到这里为什么会这样.

所以,我想我会在这里发布我的合并答案.当然,归功于那些在其他地方贡献的人.但我想回馈一些东西,并节省其他时间.

我将发布下面的脚本.但首先,这是转换的说明......

我在OS X 10.7.5 Lion上运行了脚本.Python开箱即用.

要从现有的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字段值 - 对我来说好消息是它们是,所以我可以迁移现有的生产数据.

祝好运!

UPDATE

自从进行此切换后,我注意到了之前没有注意到的问题.在我的Rails应用程序中,我的文本字段被定义为"字符串",这将贯穿数据库模式.此处概述的过程导致这些在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"(?



11> Outlaw Progr..:

我最近不得不从MySQL迁移到JavaDB以获得我们团队正在开发的项目.我发现Apache编写的一个名为DdlUtils的Java库使这很容易.它提供了一个API,可让您执行以下操作:

    发现数据库的架构并将其导出为XML文件.

    根据此架构修改数据库.

    将记录从一个DB导入到另一个DB,假设它们具有相同的模式.

我们最终得到的工具并非完全自动化,但它们运作良好.即使您的应用程序不是Java,也不应该用一些小工具来进行一次性迁移.我想我能用不到150行代码来完成迁移.

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有