Sha*_*ese 105
每个人似乎从一些greps和perl表达式开始,你有点得到一些适合你的特定数据集的东西,但你不知道它是否正确导入数据.我很惊讶没有人建立一个可以在两者之间转换的可靠库.
这里列出了我在两种文件格式之间所知的SQL语法的所有差异:以以下列开头的行:
在MySQL中没有使用
CREATE TABLE/INSERT INTO "table_name"
和MySQL使用CREATE TABLE/INSERT INTO table_name
INSERT INTO
子句中使用单引号作为字符串INSERT INTO
子句中的字符串't'
和'f'
用于布尔值,MySQL使用1
和0
(当你有一个字符串时,一个简单的正则表达式可能会失败:'我做,你不在你的内部INSERT INTO
)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;
}
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*tas 59
以下是转换器列表(自2011年以来未更新):
即你可以这样做:
Jia*_*aro 48
这是一个python脚本,基于Shalmanese的答案和Alex martelli在翻译Perl到Python的一些帮助
我正在制作社区维基,所以请随意编辑和重构,只要它不会破坏功能(谢天谢地我们可以回滚) - 这很难看但是很有效
像这样使用(假设脚本被调用dump_for_mysql.py
:
sqlite3 sample.db .dump | python dump_for_mysql.py > dump.sql
Run Code Online (Sandbox Code Playgroud)
然后你可以导入到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,
Run Code Online (Sandbox Code Playgroud)
ryw*_*ryw 22
它很混乱,因为转储文件是特定于数据库供应商的.
如果您正在使用Rails,那么就存在一个很棒的插件.阅读:http://blog.heroku.com/archives/2007/11/23/yamldb_for_databaseindependent_data_dumps/
目前维护的fork:https://github.com/ludicast/yaml_db
可能最简单的方法是使用sqlite .dump命令,在这种情况下创建示例数据库的转储.
sqlite3 sample.db .dump > dump.sql
Run Code Online (Sandbox Code Playgroud)
然后,您可以(理论上)使用用户root将其导入到mysql数据库中,在本例中是数据库服务器127.0.0.1上的测试数据库.
mysql -p -u root -h 127.0.0.1 test < dump.sql
Run Code Online (Sandbox Code Playgroud)
我在理论上说,因为语法之间存在一些差异.
在sqlite事务中开始
BEGIN TRANSACTION;
...
COMMIT;
Run Code Online (Sandbox Code Playgroud)
MySQL只使用
BEGIN;
...
COMMIT;
Run Code Online (Sandbox Code Playgroud)
还有其他类似的问题(varchars和双引号重新出现),但没有找到和替换无法修复.
也许您应该问为什么要迁移,如果性能/数据库大小是问题,或许可以看看重新构建模式,如果系统转向更强大的产品,这可能是计划数据未来的理想时间.
令人惊讶的是,现在还没有人提到这一点,但实际上有一个明确的工具.它在perl,SQL:翻译:http: //sqlfairy.sourceforge.net/
在大多数任何形式的表格数据(不同的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
Run Code Online (Sandbox Code Playgroud)
小智 8
如果您使用的是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')
Run Code Online (Sandbox Code Playgroud)
我刚刚完成了这个过程,在这个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
Run Code Online (Sandbox Code Playgroud)
然后我将生成的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
Run Code Online (Sandbox Code Playgroud)
让它做饭,那应该是它!不要忘记在之前和之后仔细检查您的数据.
所以,正如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"(?<!')'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,
Run Code Online (Sandbox Code Playgroud)
我用 Python3 编写了这个简单的脚本。它可以用作包含的类或通过终端 shell 调用的独立脚本。默认情况下,它将所有整数导入为 ,将int(11)
字符串导入为varchar(300)
,但所有这些都可以分别在构造函数或脚本参数中进行调整。
注意:它需要 MySQL Connector/Python 2.0.4 或更高版本
\n\n如果您发现下面的代码难以阅读,这里有 GitHub 上源代码的链接: https: //github.com/techouse/sqlite3-to-mysql
\n\n#!/usr/bin/env python3\n\n__author__ = "Klemen Tu\xc5\xa1ar"\n__email__ = "techouse@gmail.com"\n__copyright__ = "GPL"\n__version__ = "1.0.1"\n__date__ = "2015-09-12"\n__status__ = "Production"\n\nimport os.path, sqlite3, mysql.connector\nfrom mysql.connector import errorcode\n\n\nclass SQLite3toMySQL:\n """\n Use this class to transfer an SQLite 3 database to MySQL.\n\n NOTE: Requires MySQL Connector/Python 2.0.4 or higher (https://dev.mysql.com/downloads/connector/python/)\n """\n def __init__(self, **kwargs):\n self._properties = kwargs\n self._sqlite_file = self._properties.get(\'sqlite_file\', None)\n if not os.path.isfile(self._sqlite_file):\n print(\'SQLite file does not exist!\')\n exit(1)\n self._mysql_user = self._properties.get(\'mysql_user\', None)\n if self._mysql_user is None:\n print(\'Please provide a MySQL user!\')\n exit(1)\n self._mysql_password = self._properties.get(\'mysql_password\', None)\n if self._mysql_password is None:\n print(\'Please provide a MySQL password\')\n exit(1)\n self._mysql_database = self._properties.get(\'mysql_database\', \'transfer\')\n self._mysql_host = self._properties.get(\'mysql_host\', \'localhost\')\n\n self._mysql_integer_type = self._properties.get(\'mysql_integer_type\', \'int(11)\')\n self._mysql_string_type = self._properties.get(\'mysql_string_type\', \'varchar(300)\')\n\n self._sqlite = sqlite3.connect(self._sqlite_file)\n self._sqlite.row_factory = sqlite3.Row\n self._sqlite_cur = self._sqlite.cursor()\n\n self._mysql = mysql.connector.connect(\n user=self._mysql_user,\n password=self._mysql_password,\n host=self._mysql_host\n )\n self._mysql_cur = self._mysql.cursor(prepared=True)\n try:\n self._mysql.database = self._mysql_database\n except mysql.connector.Error as err:\n if err.errno == errorcode.ER_BAD_DB_ERROR:\n self._create_database()\n else:\n print(err)\n exit(1)\n\n def _create_database(self):\n try:\n self._mysql_cur.execute("CREATE DATABASE IF NOT EXISTS `{}` DEFAULT CHARACTER SET \'utf8\'".format(self._mysql_database))\n self._mysql_cur.close()\n self._mysql.commit()\n self._mysql.database = self._mysql_database\n self._mysql_cur = self._mysql.cursor(prepared=True)\n except mysql.connector.Error as err:\n print(\'_create_database failed creating databse {}: {}\'.format(self._mysql_database, err))\n exit(1)\n\n def _create_table(self, table_name):\n primary_key = \'\'\n sql = \'CREATE TABLE IF NOT EXISTS `{}` ( \'.format(table_name)\n self._sqlite_cur.execute(\'PRAGMA table_info("{}")\'.format(table_name))\n for row in self._sqlite_cur.fetchall():\n column = dict(row)\n sql += \' `{name}` {type} {notnull} {auto_increment}, \'.format(\n name=column[\'name\'],\n type=self._mysql_string_type if column[\'type\'].upper() == \'TEXT\' else self._mysql_integer_type,\n notnull=\'NOT NULL\' if column[\'notnull\'] else \'NULL\',\n auto_increment=\'AUTO_INCREMENT\' if column[\'pk\'] else \'\'\n )\n if column[\'pk\']:\n primary_key = column[\'name\']\n sql += \' PRIMARY KEY (`{}`) ) ENGINE = InnoDB CHARACTER SET utf8\'.format(primary_key)\n try:\n self._mysql_cur.execute(sql)\n self._mysql.commit()\n except mysql.connector.Error as err:\n print(\'_create_table failed creating table {}: {}\'.format(table_name, err))\n exit(1)\n\n def transfer(self):\n self._sqlite_cur.execute("SELECT name FROM sqlite_master WHERE type=\'table\' AND name NOT LIKE \'sqlite_%\'")\n for row in self._sqlite_cur.fetchall():\n table = dict(row)\n # create the table\n self._create_table(table[\'name\'])\n # populate it\n print(\'Transferring table {}\'.format(table[\'name\']))\n self._sqlite_cur.execute(\'SELECT * FROM "{}"\'.format(table[\'name\']))\n columns = [column[0] for column in self._sqlite_cur.description]\n try:\n self._mysql_cur.executemany("INSERT IGNORE INTO `{table}` ({fields}) VALUES ({placeholders})".format(\n table=table[\'name\'],\n fields=(\'`{}`, \' * len(columns)).rstrip(\' ,\').format(*columns),\n placeholders=(\'%s, \' * len(columns)).rstrip(\' ,\')\n ), (tuple(data) for data in self._sqlite_cur.fetchall()))\n self._mysql.commit()\n except mysql.connector.Error as err:\n print(\'_insert_table_data failed inserting data into table {}: {}\'.format(table[\'name\'], err))\n exit(1)\n print(\'Done!\')\n\n\ndef main():\n """ For use in standalone terminal form """\n import sys, argparse\n parser = argparse.ArgumentParser()\n parser.add_argument(\'--sqlite-file\', dest=\'sqlite_file\', default=None, help=\'SQLite3 db file\')\n parser.add_argument(\'--mysql-user\', dest=\'mysql_user\', default=None, help=\'MySQL user\')\n parser.add_argument(\'--mysql-password\', dest=\'mysql_password\', default=None, help=\'MySQL password\')\n parser.add_argument(\'--mysql-database\', dest=\'mysql_database\', default=None, help=\'MySQL host\')\n parser.add_argument(\'--mysql-host\', dest=\'mysql_host\', default=\'localhost\', help=\'MySQL host\')\n parser.add_argument(\'--mysql-integer-type\', dest=\'mysql_integer_type\', default=\'int(11)\', help=\'MySQL default integer field type\')\n parser.add_argument(\'--mysql-string-type\', dest=\'mysql_string_type\', default=\'varchar(300)\', help=\'MySQL default string field type\')\n args = parser.parse_args()\n\n if len(sys.argv) == 1:\n parser.print_help()\n exit(1)\n\n converter = SQLite3toMySQL(\n sqlite_file=args.sqlite_file,\n mysql_user=args.mysql_user,\n mysql_password=args.mysql_password,\n mysql_database=args.mysql_database,\n mysql_host=args.mysql_host,\n mysql_integer_type=args.mysql_integer_type,\n mysql_string_type=args.mysql_string_type\n )\n converter.transfer()\n\nif __name__ == \'__main__\':\n main()\n
Run Code Online (Sandbox Code Playgroud)\n
我最近不得不从MySQL迁移到JavaDB以获得我们团队正在开发的项目.我发现Apache编写的一个名为DdlUtils的Java库使这很容易.它提供了一个API,可让您执行以下操作:
我们最终得到的工具并非完全自动化,但它们运作良好.即使您的应用程序不是Java,也不应该用一些小工具来进行一次性迁移.我想我能用不到150行代码来完成迁移.
moose@pc08$ sqlite3 mySqliteDatabase.db .dump > myTemporarySQLFile.sql
Run Code Online (Sandbox Code Playgroud)
moose@pc08$ mysql -u <username> -p
Enter password:
....
mysql> use somedb;
Database changed
mysql> source myTemporarySQLFile.sql;
Run Code Online (Sandbox Code Playgroud)
或者
mysql -u root -p somedb < myTemporarySQLFile.sql
Run Code Online (Sandbox Code Playgroud)
这将提示您输入密码。请注意:如果您想直接输入密码,则必须在没有空格的情况下直接输入-p
:
mysql -u root -pYOURPASS somedb < myTemporarySQLFile.sql
Run Code Online (Sandbox Code Playgroud)
mysqlimport 或其他导入工具,如BigDump。
BigDump 给你一个进度条:
归档时间: |
|
查看次数: |
258944 次 |
最近记录: |