问答中心分类: MYSQL将 SQLite3 迁移到 MySQL 的快速简便方法?
0
Jiaaro 提问 21分钟 前

关闭.这个问题需要多专注.它目前不接受答案。

想改进这个问题?更新问题,使其仅关注一个问题编辑这篇文章.

关闭2年前.

社区审核是否重开这个问题12 个月前并将其关闭:

原始关闭原因未解决

改进这个问题

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

15 Answers
0
Shalmanese 回答 21分钟 前

每个人似乎都是从一些 grep 和 perl 表达式开始的,你有点得到适用于你的特定数据集的东西,但你不知道它是否正确导入了数据。我很惊讶没有人建立一个可以在两者之间转换的可靠库。
这里列出了我所知道的两种文件格式之间的所有 SQL 语法差异: 以:

  • 开始交易
  • 犯罪
  • sqlite_sequence
  • 创建唯一索引

未在 MySQL 中使用

  • SQLite 使用CREATE TABLE/INSERT INTO "table_name"和 MySQL 使用CREATE TABLE/INSERT INTO table_name
  • MySQL 不在模式定义中使用引号
  • MySQL 对内部的字符串使用单引号INSERT INTO条款
  • SQLite 和 MySQL 有不同的内部转义字符串的方法INSERT INTO条款
  • SQLite 使用'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_]*)\"(.*)/i){
            $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_]*)\"(.*)/i){
            $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;
    }
}
Jiaaro 回复 21分钟 前

亚历克斯·马泰利(Alex martelli)在将其重写为 python 时做得很好stackoverflow.com/questions/1067060/perl-to-python

Jiaaro 回复 21分钟 前

我添加了完整的 python 脚本(单独的 perl 脚本对我来说不太有效……需要一些额外的处理来处理外键和索引)

Brad Gilbert 回复 21分钟 前

我在另一个问题上重写了这个答案stackoverflow.com/questions/1067060/_/1070463#1070463

PCoder 回复 21分钟 前

+1 添加到第二条评论中所说的内容,我不得不删除PRAGMA foreign_keys=OFF;

niutech 回复 21分钟 前

犯罪创建唯一索引是有效的 MySQL 命令,请修复它。

Bula 回复 21分钟 前

注意:默认十进制为 (10,0),因此如果您需要其他格式的十进制字段,则应手动插入。

Michał Leon 回复 21分钟 前

我了解您的脚本“又快又脏”,但也非常有用,所以这里有一些补充/错误修正: * 之后&& ($line !~ /CREATE UNIQUE INDEX/)添加&& ($line !~ /PRAGMA foreign_keys=OFF/)* 表名匹配的正则表达式缺少数字,而不是$line =~ /INSERT INTO \"([a-z_]*)\"(.*)/必须有$line =~ /INSERT INTO \"([a-z_1-9]*)\"(.*)/希望这对未来的读者有所帮助

FranciscoBouza 回复 21分钟 前

此外,要在列上使用默认值,请省略括号:..., column_name INTEGER DEFAULT 1234, ...

Jon Weinraub 回复 21分钟 前

使用 Perl 脚本出现错误:ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'FFT, Comment TEXT, FOREIGN KEY (SerialNumberRecordID) REFERENCES SerialNumTable' at line 6.我用我用.\script.pl foo.sql > out.sql作为它的用法?

0
Jiaaro 回答 21分钟 前

这是一个 python 脚本,建立在 Shalmanese 的回答和 Alex martelli 的一些帮助之上将 Perl 翻译成 Python
我正在制作它的社区 wiki,所以请随时编辑和重构,只要它不破坏功能(谢天谢地我们可以回滚) – 它非常丑陋但有效
像这样使用(假设脚本被调用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'(.)", "THIS_IS_TRUE", line)
    line = line.replace('THIS_IS_TRUE', '1')
    line = re.sub(r"([^'])'f'(.)", "THIS_IS_FALSE", 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,
David 回复 20分钟 前

嗨,吉姆,在我的数据集上,每个第一个 INSERT 语句都用反引号而不是单引号括起来:__ DROP TABLE IF EXISTS schema_migrations;如果不存在则创建表schema_migrations(versionvarchar(255) 非空);插入到 schema_migrations 值(20100714032840);插入模式迁移值(’20100714033251’); __

David 回复 20分钟 前

好吧……它没有显示在上面,但反引号出现在 VALUES 内([HERE]20100714032840[/HERE])

gdm 回复 20分钟 前

Mysql 中的 AUTOINCREMENT 是 AUTO_INCREMENT。脚本没有说明这一点。

Frank Hintsch 回复 20分钟 前

这不适用于媒体 wiki 数据库。很多错误:Blobvar数据类型,CREATE 语句中的反引号 …

Himanshu Bansal 回复 20分钟 前

不起作用。可能不是所有条件都考虑在内…

Jonathas Hortense 回复 20分钟 前

转换后我必须手动修复一些东西(例如,auto_increment),但它对我有用。

JackTheKnife 回复 20分钟 前

令人惊讶的是,这个版本比 Alex 的代码有更多的问题

El' 回复 20分钟 前

在使用 utf8 编码的 json 的字符串上失败,之前:{"city": "\u043a\u0438\u0457\u0432"}后:{"city":"u043au0438u0457u0432"}

Oliver P 回复 20分钟 前

如果使用python3,则需要将最后一行更新为: print(line),

0
Vincent Sit 回答 20分钟 前

我通常使用导出/导入表的特点IntelliJ DataGrip.
步骤1
第2步
第 3 步
您可以在右下角看到进度。
[在此处输入图像描述]

Rexave 回复 20分钟 前

此方法不会将索引迁移到新的数据库表

0
Mihkorz 回答 20分钟 前

如果您使用的是 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')
0
Richard Gourlay 回答 20分钟 前

可能最快最简单的方法是使用 sqlite .dump 命令,在这种情况下创建示例数据库的转储。

sqlite3 sample.db .dump > dump.sql

然后,您可以(理论上)将其导入 mysql 数据库,在本例中为数据库服务器 127.0.0.1 上的测试数据库,使用用户 root。

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

我说理论上是因为语法之间存在一些差异。
在 sqlite 事务开始

BEGIN TRANSACTION;
...
COMMIT;

MySQL 只使用

BEGIN;
...
COMMIT;

还有其他类似的问题(varchars 和双引号回想起),但没有什么 find 和 replace 无法解决。
也许您应该问为什么要迁移,如果性能/数据库大小是问题,或者考虑重新设计模式,如果系统正在转向更强大的产品,这可能是为您的数据的未来进行规划的理想时机。

francois 回复 20分钟 前

但最困难的任务是区别 betweek 语法