脚本将mysql转储sql文件转换成可以导入到sqlite3数据库的格式

我有一个导出SQL文件,其中包含来自MySQL的表和数据,我想将其导入到Sqlite 3数据库。

什么是最好的方法来做到这一点?

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

这个shell脚本可以帮助你

#!/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 

为了使上面的脚本起作用,我做了以下更改:

  1. 用#!/ bin / bash运行
  2. 将两个seds添加到stream水线seds列表中:
    • sed's / \\ r \\ n / \\ n / g'
    • sed's / \\“/”/ g'
  3. 'rm tmp'行是一个空操作(除非你有一个名为'tmp'的文件位于:O)
  4. 我的mysqldump命令如下所示:

    $ mysqldump -u usernmae -h host –compatible = ansi –skip-opt -p database_name> dump_file

然后它很好地工作…感谢脚本。

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

然后,我发现Perl模块SQL :: Translator “将供应商特定的SQL表定义转换为其他格式…”
这个模块创build所有的外键和更正索引,如果必要的话更改名称。

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

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

在其他testing中,我有问题与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 > "; } 

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

这很容易解决:

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

Incase这有助于某人。

当sqlite3数据库将与ruby一起使用时,您可能需要更改:

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

至less,在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数据库(生产)复制到Ruby On Rails应用程序的sqlite3数据库(开发),我不得不添加以下行以设置一个自动递增的主键:

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

我仍然试图找出一种方法来从MySQL更改KEY条目到其相应的CREATE INDEX条目的sqlite3。

为了在数据库中转换BLOB,我在mysqldump命令中添加了–hex-blob,在pipe道化的seds列表中添加了以下内容:

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

这取代了MySQL的hex转储string,例如0x010A …。 用X'010a …'用sqlite导入。

这是将ssql转换为.db的最好的书面和有据可查的shell脚本

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 :) 

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

shell> sqlite3 file_name.db SQLite version 3.3.6input“.help”作为指令sqlite> .databases seq name file


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