2009-01-28 61 views
20

我有一个包含来自MySQL的表和数据的导出SQL文件,我想将它导入到Sqlite 3 DB中。将mysql转储sql文件转换为可导入sqlite3格式的脚本db

这样做的最好方法是什么?

只是通过sqlite3工具导入文件不起作用。

+0

我已经建立了一个泊坞窗容器续集一个衬垫数据库转换https://blog.chib.me/how-to-convert-databases-with-一行代码/ – 2016-02-07 13:07:05

回答

24

这个你

#!/bin/sh 
if [ "x$1" == "x" ]; then 
    echo "Usage: $0 <dumpname>" 
    exit 
fi 
cat $1 | 
grep -v ' KEY "' | 
grep -v ' UNIQUE KEY "' | 
grep -v ' PRIMARY KEY ' | 
sed '/^SET/d' | 
sed 's/ unsigned//g' | 
sed 's/ auto_increment/ primary key autoincrement/g' | 
sed 's/ smallint([0-9]*)/integer /g' | 
sed 's/ tinyint([0-9]*)/integer /g' | 
sed 's/ int([0-9]*)/integer /g' | 
sed 's/ character set [^ ]*//g' | 
sed 's/ enum([^)]*)/varchar(255) /g' | 
sed 's/ on update [^,]*//g' | 
perl -e 'local $/;$_=<>;s/,\n\)/\n\)/gs;print "begin;\n";print;print "commit;\n"' | 
perl -pe ' 
    if (/^(INSERT.+?)\(/) { 
    $a=$1; 
    s/\\'\''/'\'\''/g; 
    s/\\n/\n/g; 
    s/\),\(/\);\n$a\(/g; 
    } 
    ' > $1.sql 
cat $1.sql | sqlite3 $1.db > $1.err 
ERRORS=`cat $1.err | wc -l` 
if [ $ERRORS == 0 ]; then 
    echo "Conversion completed without error. Output file: $1.db" 
    rm $1.sql 
    rm $1.err 
    rm tmp 
else 
    echo "There were errors during conversion. Please review $1.err and $1.sql for details." 
fi 
+0

嗨,当我运行这个脚本,我得到错误,因为它不明白如果在fi。我将#!/ bin/sh更改为#!/ bin/sh,它绕过它。但脚本只是删除sql转储文件并写入一个空的.db文件。 – DEzra 2009-01-29 14:36:07

+4

这里是一个稍微更新和Mac测试版本:https://gist.github.com/741043 – miku 2010-12-14 20:28:54

7

要得到上面的脚本工作,我做了如下修改shell脚本的帮助:

  1. 与#来看,它/斌/庆典
  2. 添加两个SEDS到流水线SEDS的列表:
    • SED的/ \\ř\\ N/\\ N/G'
    • SED的/ \\ “/”/ G'
  3. 的 'RM TMP' 行无操作(除非你有一个名为 'TMP' 躺在身边文件:O)
  4. 我mysqldump的命令是这样的:

    $的mysqldump -u usernmae -h主机--compatible = ANSI --skip-OPT -p数据库名称> dump_file

然后它的工作很好...感谢脚本。

0

在Centos 5.3 64bit上正常工作。一旦你的输出文件加载像这样:

外壳> sqlite3的file_name.db SQLite的版本3.3.6 的指令输入 “帮助” sqlite的> .databases 以次名文件


0 main /current_directory/file_name.db
sqlite> select * from table; 。 。 。 。 。 结果... sqlite的> .quit

1

当sqlite3的数据库将与红宝石使用您可能需要更改:

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文件来查找所有布尔值是有帮助的。

2

我有一个MySQL数据库是ISO-8859-1(Latin-1)的问题。转换到sqlite3的时候假设数据是UTF-8导致解码错误。

这是很容易与此修复:

的iconv -f ISO-8859-1 -t UTF-8 mysql_dump_file> mysql_dump_file_utf8

柜面这可以帮助别人。

1

至少,在mysql 5.0.x中,我必须从mysql的转储中删除collat​​e utf8_unicode_ci,然后再将其导入到sqlite3。所以我修改剧本,包括以下内容SEDS名单:

sed 's/ collate utf8_unicode_ci/ /g' |

更新:

的MySQL把布尔字段为“TINYINT(1)”,所以我不得不添加以下tinyint([0-9]*)的sed:

sed 's/ tinyint(1)/boolean /g' |

而且,因为我试图复制一个MySQL数据库(生产)到sqlite3的DB一个Ruby on Rails应用程序的(开发),我不得不添加以下行,以设置自动递增的主键:

sed 's/) NOT NULL/) PRIMARY KEY AUTOINCREMENT NOT NULL/g' |

我仍然在试图找出一种方法来改变KEY从mysql到其对应的条目CREATE INDEX条目的sqlite3。

5

我尝试了一些使用sed或awk的脚本,但总是出现错误,可能是由于我的MySQL数据库的索引和外键以及所需的mysqldump选项。

然后我发现了Perl模块,SQL::Translator“是供应商特定的SQL表定义转换为其他格式...”
该模块创建所有外键和纠正索引,如果改变的necesssary名字。

因此,我重写了shell脚本,包括MySQL数据库的转储。 有两个转储,因为脚本“sqlt”只生成结构并且在转储没有数据时工作得很快。 请注意,它可以适用于由SQL :: Translator支持的其他转换。

当我发布这个shell脚本后,我意识到问题是要转换一个MySQL转储文件, ,所以我做了一个Perl脚本,使用模块SQL :: Translator。在我的测试中,我使用了无选项生成的转储文件(mysqldump -u用户 - 密码数据库>转储文件)。 我没有字符集的问题。

在其他测试中,我有问题与MySQL触发器,所以我改变了脚本跳过它。

#!/bin/sh 
#=============================================================================== 
#   USAGE: ./mysql2sqlite.sh <MySQL_database> <user> 
# DESCRIPTION: Converts MySQL databases to SQLite 
#    Triggers are not converted 
# REQUIREMENTS: mysqldump, Perl and module SQL::Translator, SQLite 
#=============================================================================== 
if [ "$#" = 2 ]; then 
    USER="$2"  
else 
    echo "Usage: $0 <MySQL_database> <user>" 
    exit 
fi 
if [ -s $1.db ]; then 
    read -p "File <$1.db> exists. Overwrite? [y|n] " ANS 
    if [ "$ANS" = "y" ] || [ "$ANS" = "Y" ] ; then 
     rm $1.db 
    else 
     echo "*** Aborting..." 
     exit 
    fi 
fi 
# extracts the necessary structure for SQLite: 
mysqldump --skip-triggers --skip-add-locks --routines --no-data --compatible=ansi \ 
    --compact -u $USER --password $1 > /tmp/$1_$$_str.sql 
# verify 
if [ ! -s /tmp/$1_$$_str.sql ]; then 
    echo "*** There are some problem with the dump. Exiting." 
    exit 
fi 
# translates MySQL syntax structure to SQLite using the script "sqlt" of the 
# perl module SQL::Translator (that corrects the foreign keys, indexes, etc.) 
sqlt -f MySQL -t SQLite --show-warnings /tmp/$1_$$_str.sql \ 
    1> /tmp/$1_$$.sqlite 2> /tmp/$1_$$_sqlt.log 
# verify 
if [ ! -s /tmp/$1_$$.sqlite ]; then 
    echo "*** There are some problem with the sql translation. Exiting." 
    exit 
fi 
# adds statements to allow to load tables with foreign keys: 
echo "PRAGMA foreign_keys=OFF;" >> /tmp/$1_$$.sqlite 
echo "BEGIN TRANSACTION;" >> /tmp/$1_$$.sqlite 
# extracts the data (simple inserts) without locks/disable keys, 
# to be read in versions of SQLite that do not support multiples inserts: 
mysqldump --skip-triggers --no-create-db --no-create-info --skip-add-locks \ 
    --skip-extended-insert --compatible=ansi --compact -u $USER \ 
    --password $1 >> /tmp/$1_$$.sqlite 
# adds statements to finish the transaction: 
echo "COMMIT;" >> /tmp/$1_$$.sqlite 
echo "PRAGMA foreign_keys=ON;" >> /tmp/$1_$$.sqlite 
# correct single quotes in inserts 
perl -pi -e ' if (/^INSERT INTO/) { s/\\'\''/'\'\''/g; } ' /tmp/$1_$$.sqlite 
# load the sql file and generate the SQLite db with the same name 
# of the MySQL database 
sqlite3 $1.db < /tmp/$1_$$.sqlite 2> /tmp/$1_$$sqlite.errlog 
# verify 
ERRORS=`cat /tmp/$1_$$sqlite.errlog | wc -l` 
if [ $ERRORS = 0 ]; then 
    echo "* Conversion complete. Verify the file < $1.db >" 
    rm /tmp/$1_$$* 
else 
    echo "*** There are some problem. Verify the files < /tmp/$1_$$* >" 
fi 

这里的Perl脚本到转储文件转换成一个SQLite数据库文件。

#!/usr/bin/perl 
#=============================================================================== 
#  USAGE: ./mysql2sqlite.pl <MySQL_dumpfile> 
# DESCRIPTION: Converts MySQL dumpfile to SQLite database 
#    Triggers are not converted 
#    The dump must be done with 
#    > mysqldump --skip-triggers -u [user] --p [database] > dumpfile 
# REQUIREMENTS: Perl and module SQL::Translator, SQLite 
#=============================================================================== 
use strict; 
use warnings; 
use Carp; 
use English qw(-no_match_vars); 
use SQL::Translator; 
use 5.012; 

my $file = $ARGV[0]; 
my $filedb = $file; 
$filedb =~ s/\.*[^.]*$/.db/; 
if (-s $filedb) { 
    say "*** Ja existe o arquivo < $filedb >. Abandonando..."; 
    exit; 
} 
my @stru; 
my @data; 

open(my $SQLFILE, "<", $file) 
    or croak "Can't open $file: $OS_ERROR"; 
while (<$SQLFILE>) { 
    # nao considera linhas com comentarios e lock/unlock/drop 
    next if (/^--/ || /^\/\*/ || /^lock/i || /^unlock/i || /^drop/i); 
    # processa os inserts 
    if (/^(INSERT.+?)[(]/) {  
     my $ins = $1;   # captura o nome da tabela 
     s/\\[']/''/g;   # substitue aspas simples - \' 
     s/[)],[(]/);\n$ins(/g; # divide multiplos inserts 
     push(@data, $_); 
    } 
    # processa a estrutura 
    else { push(@stru, $_); } 
} 
close($SQLFILE); 

my $strusql = join('', @stru); 
my $datasql = join('', @data); 
#open(my $STRU, ">", "stru.sql"); # to verify the results 
#open(my $DATA, ">", "data.sql"); 
#print $STRU $strusql; 
#print $DATA $datasql; 

# here the conversion 
my $translator = SQL::Translator->new(
    no_comments  => 0, 
    show_warnings  => 0, 
    quote_table_names => 1, 
    quote_field_names => 1, 
    validate   => 1, 
); 
my $struout = $translator->translate(
    from => 'MySQL', 
    to => 'SQLite', 
    data => \$strusql, 
    # filename => $file, 
) or croak "Error: " . $translator->error; 

# define inicio e final da transacao de inserts 
my $prgini = "PRAGMA foreign_keys=OFF;\n"; 
my $traini = "BEGIN TRANSACTION;\n"; 
my $trafin = "COMMIT;\n"; 
my $prgfin = "PRAGMA foreign_keys=ON;\n"; 

#gera o arquivo final sqlite 
my $sqlout = join("\n", $struout, $prgini, $traini, $datasql, $trafin, $prgfin); 
open(my $FINAL, ">", "/tmp/final.sql"); 
print $FINAL $sqlout; 

# Monta o SQLite database 
my $log = "/tmp/sqlite.errlog"; 
my $command = "sqlite3 $filedb < /tmp/final.sql 2> $log"; 
system($command) == 0 or die "system $command failed: $?"; 
if (-s $log) { 
    say "*** Houve algum problema. Verifique o arquivo </tmp/sqlite.errlog> "; 
} 
else { 
    say "*** Conversao completa. Verifique o arquivo < $filedb > "; 
} 

1

将数据库转换,在他们的BLOB我加--hex-的blob mysqldump命令和下面,以流水线SEDS名单: -

sed -e "s/,0x\([0-9A-Z]*\),/,X'\L\1',/g" | 

这将替换mysql十六进制转储字符串例如0x010A时...。用X'010a ...'用sqlite导入。

1

这是写得最好的,有据可查的shell脚本转换ssql到.DB

https://gist.github.com/esperlu/943776

或更好地运用这个工具,这是惊人的和快速ESF数据库迁移工具包

在尝试过所有的脚本之后,直到我使用esf工具后才开始工作。

注:

Trial version add a 'T' to the begingn of each text value you have 
But the pro version worked like a charm :)