скрипт для преобразования файла sql mysql в формат, который можно импортировать в sqlite3 db - PullRequest
20 голосов
/ 28 января 2009

У меня есть файл экспорта SQL, содержащий таблицы и данные из MySQL, и я хочу импортировать его в БД Sqlite 3.

Каков наилучший способ сделать это?

Простой импорт файла с помощью инструмента sqlite3 не работает.

Ответы [ 9 ]

23 голосов
/ 28 января 2009

Этот скрипт поможет вам

#!/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
7 голосов
/ 25 июня 2009

Чтобы заставить работать вышеуказанный скрипт, я внес следующие изменения:

  1. запустите его с #! / Bin / bash
  2. добавить два seds в список конвейерных seds:
    • sed 's / \\ r \\ n / \\ n / g'
    • sed 's / \\ "/" / g'
  3. строка 'rm tmp' запрещена (если у вас нет файла с именем 'tmp': O)
  4. моя команда mysqldump выглядела так:

    $ mysqldump -u usernmae -h хост --compatible = ansi --skip-opt -p имя_базы_данных> файл_дампа

Тогда все заработало ... спасибо за скрипт.

5 голосов
/ 25 марта 2012

Я пробовал некоторые из этих сценариев, которые используют sed или awk, но всегда происходит ошибка, возможно, из-за индексов и внешних ключей моей базы данных MySQL и необходимых параметров mysqldump.

Затем я обнаружил модуль Perl SQL :: Translator", который преобразует определения таблиц SQL конкретного поставщика в другие форматы ..."
Этот модуль создает все внешние ключи и корректирует индексы, меняя имена, если это необходимо.

Итак, я переписал сценарий оболочки, включая дамп базы данных MySQL. Существует два дампа, потому что скрипт «sqlt» только генерирует структуру и работает быстро, если у дампа нет данных. Обратите внимание, что он может быть адаптирован к другим преобразованиям, поддерживаемым SQL :: Translator.

После того, как я опубликовал этот сценарий оболочки, я понял, что вопрос заключается в том, чтобы конвертировать дамп-файл MySQL, поэтому я сделал Perl-скрипт, который делает это, используя модуль SQL :: Translator. В своих тестах я использовал дамп-файл, сгенерированный без опций ( 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

Здесь скрипт 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 > "; 
}

2 голосов
/ 28 октября 2010

У меня была проблема с mysql db, являющимся ISO-8859-1 (Latin-1). Когда преобразование в sqlite3 предполагало, что данные были в формате UTF-8, что приводило к ошибкам декодирования.

Это было легко исправить с помощью:

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

Если это кому-нибудь поможет.

1 голос
/ 04 июня 2013

Это лучший написанный и хорошо документированный сценарий оболочки для преобразования ssql в .db

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

или лучше используйте эти инструменты. Это удивительно и быстро ESF Database Migration Toolkit .

после того, как попробовал весь скрипт, он не работал, пока я не использовал инструмент esf.

Примечание:

Trial version add a 'T' to the begingn of each text value you have 
 But the pro version worked like a charm :)
1 голос
/ 13 февраля 2013

Чтобы преобразовать базы данных с BLOB-объектами в них, я добавил --hex-blob к команде mysqldump и следующее к списку конвейерных seds: -

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

это заменяет строки шестнадцатеричного дампа mysql, например 0x010A .... с X’010a… ’для импорта с помощью sqlite.

1 голос
/ 17 июля 2011

По крайней мере, в mysql 5.0.x мне пришлось удалить collate utf8_unicode_ci из дампа mysql перед импортом в sqlite3. Поэтому я изменил скрипт, добавив в список seds следующее:

sed 's/ collate utf8_unicode_ci/ /g' |

Обновление:

MySQL рассматривает логические поля как "tinyint (1)", поэтому мне пришлось добавить следующее перед tinyint([0-9]*) sed:

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

Кроме того, поскольку я пытаюсь реплицировать mysql db (производство) в sqlite3 db (разработка) приложения Ruby On Rails, мне пришлось добавить следующую строку, чтобы установить автоинкрементный первичный ключ:

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

Я все еще пытаюсь найти способ изменить записи KEY с mysql на соответствующую CREATE INDEX запись sqlite3.

1 голос
/ 30 марта 2010

Когда база данных 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 для просмотра, чтобы найти все логические значения.

0 голосов
/ 09 января 2010

отлично работает на Centos 5.3 64bit. когда у вас есть выходной файл, загрузите его так:

shell> sqlite3 file_name.db SQLite версия 3.3.6 Введите ".help" для получения инструкций sqlite> .database имя файла seq


0 main /current_directory/file_name.db
sqlite> select * from table; , , , , , Результаты... SQLite> .quit

...