script to convert mysql dump sql file into format that can be imported into sqlite3 db

后端 未结 9 2223
说谎
说谎 2020-11-29 03:07

I have an export SQL file containing tables and data from MySQL and I want to import it into a Sqlite 3 DB.

What is the best way to do that?

Just importing t

9条回答
  •  天命终不由人
    2020-11-29 03:27

    I tried some of these scripts that uses sed or awk, but always occurs an error, probably due to the indexes and foreign keys of my MySQL db and the mysqldump options needed.

    Then I found the Perl module SQL::Translator "that converts vendor-specific SQL table definitions into other formats..."
    This module create all foreign keys and correct the indexes, changing the names if necesssary.

    So, I rewrite the shell script, including the dump of the MySQL db. There are two dumps because the script "sqlt" only generates the structure and works fast if the dump has no data. Note that it can be adapted to others conversions suported by the SQL::Translator.

    After I posted this shell script I realized that the question is about to convert a MySQL dumpfile, so I did a Perl script that do that, using the module SQL::Translator. In my tests, I used a dumpfile generated without options (mysqldump -u user --password database > dumpfile). I had no problems with character sets.

    In other test I had problem with mysql triggers, so I altered the scripts to skip it.

    #!/bin/sh
    #===============================================================================
    #         USAGE: ./mysql2sqlite.sh  
    #   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  "
        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
    

    Here the Perl script to convert a dumpfile in a SQLite database file.

    #!/usr/bin/perl 
    #===============================================================================
    #        USAGE: ./mysql2sqlite.pl 
    #  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 > "; 
    }
    

提交回复
热议问题