【问题标题】:script to convert mysql dump sql file into format that can be imported into sqlite3 db将mysql转储sql文件转换为可以导入sqlite3 db的格式的脚本
【发布时间】:2010-10-04 02:35:21
【问题描述】:

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

最好的方法是什么?

仅仅通过 sqlite3 工具导入文件是行不通的。

【问题讨论】:

标签: mysql sqlite mysqldump


【解决方案1】:

这个 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

【讨论】:

  • 嗨,当我运行这个脚本时,我收到错误,因为它不理解 if 中的 fi。我将#!/bin/sh 更改为#!/bin/sh,它绕过了它。但是脚本只是删除了sql转储文件并写入了一个空的.db文件。
  • 这里是一个稍微更新并经过 Mac 测试的版本:gist.github.com/741043
  • 我需要在 "grep -v ' PRIMARY KEY ' |" 之后添加以下两行使其工作: grep -v '^LOCK TABLES' | grep -v '^解锁表;' |除此之外,效果很好!谢谢!
  • 这个脚本对我有用。但是,我遇到了 SQL 本身的问题,转储中包含 sqlite 无法读取的值,例如 'foo\'s bar'。
  • 我不得不添加更多内容 - AUTO_INCREMENT 是大写的,还有 DEFAULT CHARSET 设置和 ENGINE 设置。
【解决方案2】:

为了使上述脚本正常工作,我做了以下更改:

  1. 用#!/bin/bash 运行它
  2. 将两个 sed 添加到流水线 sed 列表中:
    • 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

然后它运行良好...感谢脚本。

【讨论】:

    【解决方案3】:

    在 Centos 5.3 64 位上运行良好。一旦你有输出文件,像这样加载它:

    shell> sqlite3 文件名.db SQLite 版本 3.3.6 输入“.help”获取说明 sqlite> .databases 序列名称文件


    0 主 /current_directory/file_name.db
    sqlite> 从表中选择 *; . . . . . 结果... sqlite>.退出

    【讨论】:

      【解决方案4】:

      当 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 文件以查找所有布尔值很有帮助。

      【讨论】:

        【解决方案5】:

        我的 mysql 数据库是 ISO-8859-1 (Latin-1) 时遇到问题。何时转换为 sqlite3 假定数据为 UTF-8 导致解码错误。

        用这个很容易解决:

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

        以防这对某人有所帮助。

        【讨论】:

          【解决方案6】:

          至少,对于 mysql 5.0.x,我必须在将其导入 sqlite3 之前从 mysql 的转储中删除 collat​​e utf8_unicode_ci。所以我修改了脚本,将以下内容添加到 seds 列表中:

          sed 's/ collate utf8_unicode_ci/ /g' |

          更新:

          MySQL 将布尔字段视为“tinyint(1)”,所以我必须在 before 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' |

          我仍在尝试找出一种方法将 KEY 条目从 mysql 更改为 sqlite3 的相应 CREATE INDEX 条目。

          【讨论】:

            【解决方案7】:

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

            然后我找到了 Perl 模块 SQL::Translator“它将特定于供应商的 SQL 表定义转换为其他格式...”
            该模块创建所有外键并更正索引,必要时更改名称。

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

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

            在其他测试中,我遇到了 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
            

            这里是转换 SQLite 数据库文件中的转储文件的 Perl 脚本。

            #!/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 > "; 
            }
            

            【讨论】:

            • 我在上面的 shell 脚本中遇到了问题,但是这个 perl 程序运行良好!
            • 不幸的是,这个 perl 脚本会导致无限的内存泄漏,我的整个系统会在几秒钟内停止。 (我要编辑的文件是 POD 数据库,来自product-open-data.com/download)
            【解决方案8】:

            为了转换其中包含 BLOB 的数据库,我将 --hex-blob 添加到 mysqldump 命令中,并将以下内容添加到流水线 seds 列表中:-

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

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

            【讨论】:

              【解决方案9】:

              这是将 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 :)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-09-14
                • 2015-11-08
                • 1970-01-01
                • 2014-08-26
                • 2011-02-07
                • 2015-01-21
                • 1970-01-01
                • 2020-09-28
                相关资源
                最近更新 更多