script pour convertir mysql dump fichier sql dans le format qui peut être importé dans sqlite3 db
9 réponses
ce script shell vous aide
#!/bin/sh
if [ "x" == "x" ]; then
echo "Usage: "151900920" <dumpname>"
exit
fi
cat |
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=;
s/\'\''/'\'\''/g;
s/\n/\n/g;
s/\),\(/\);\n$a\(/g;
}
' > .sql
cat .sql | sqlite3 .db > .err
ERRORS=`cat .err | wc -l`
if [ $ERRORS == 0 ]; then
echo "Conversion completed without error. Output file: .db"
rm .sql
rm .err
rm tmp
else
echo "There were errors during conversion. Please review .err and .sql for details."
fi
pour que le script ci-dessus fonctionne, j'ai fait les changements suivants:"
- exécuter avec #!/ bin /bash
- ajouter deux seds à la liste des seds pipelinés:
- sed 's/\\r\\n/\\n/g'
- sed 's / \\" / "/ g'
- la ligne 'rm tmp' est une No-op (à moins que vous ayez un fichier nommé 'tmp' qui traîne :O)
-
ma commande mysqldump ressemble à ceci:
$ mysqldump -u usernmae-h host --compatible=ansi --skip-opt -P database_name > dump_file
alors ça a bien marché... merci pour le script.
j'ai essayé certains de ces scripts qui utilisent sed ou awk, mais il se produit toujours une erreur, probablement en raison des index et des clés étrangères de ma base de données MySQL et des options mysqldump nécessaires.
puis j'ai trouvé le module Perl SQL::Translator "qui convertit les définitions de table SQL spécifiques au vendeur dans d'autres formats..."
Ce module crée toutes les clés étrangères et corrige les index, en changeant les noms si nécessaire.
donc, j'ai réécrit le script shell, y compris le dump De La base de données MySQL. Il y a deux dumps car le script "sqlt" ne génère la structure et ne fonctionne rapidement que si le dump n'a pas de données. Notez qu'il peut être adapté à d'autres conversions supportées par le traducteur SQL::.
après avoir posté ce script shell, j'ai réalisé que la question était sur le point de convertir un fichier dump MySQL, donc j'ai fait un script Perl qui fait ça, en utilisant le module SQL::Translator. Dans mes tests, j'ai utilisé un fichier dump généré sans options ( mysqldump-u user --password database > dumpfile ). Je n'avais pas de problèmes avec les jeux de caractères.
dans un autre test, j'ai eu des problèmes avec les déclencheurs mysql, donc j'ai modifié les scripts pour les sauter.
#!/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=""
else
echo "Usage: "151900920" <MySQL_database> <user>"
exit
fi
if [ -s .db ]; then
read -p "File <.db> exists. Overwrite? [y|n] " ANS
if [ "$ANS" = "y" ] || [ "$ANS" = "Y" ] ; then
rm .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 > /tmp/_$$_str.sql
# verify
if [ ! -s /tmp/_$$_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/_$$_str.sql \
1> /tmp/_$$.sqlite 2> /tmp/_$$_sqlt.log
# verify
if [ ! -s /tmp/_$$.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/_$$.sqlite
echo "BEGIN TRANSACTION;" >> /tmp/_$$.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 >> /tmp/_$$.sqlite
# adds statements to finish the transaction:
echo "COMMIT;" >> /tmp/_$$.sqlite
echo "PRAGMA foreign_keys=ON;" >> /tmp/_$$.sqlite
# correct single quotes in inserts
perl -pi -e ' if (/^INSERT INTO/) { s/\'\''/'\'\''/g; } ' /tmp/_$$.sqlite
# load the sql file and generate the SQLite db with the same name
# of the MySQL database
sqlite3 .db < /tmp/_$$.sqlite 2> /tmp/_$$sqlite.errlog
# verify
ERRORS=`cat /tmp/_$$sqlite.errlog | wc -l`
if [ $ERRORS = 0 ]; then
echo "* Conversion complete. Verify the file < .db >"
rm /tmp/_$$*
else
echo "*** There are some problem. Verify the files < /tmp/_$$* >"
fi
voici le script Perl pour convertir un fichier dumpfile dans un fichier de base de données 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 = ; # 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 > ";
}
j'ai eu un problème avec le fait que la base de données mysql soit ISO-8859-1 (Latin-1). Quand est-ce que la conversion en sqlite3 a supposé que les données étaient UTF-8 résultant en erreurs de décodage.
il était facile de fixer avec ceci:
iconv-F ISO-8859-1 -T UTF-8 mysql_dump_file > mysql_dump_file_utf8
au cas où cela aiderait quelqu'un.
lorsque la base de données sqlite3 sera utilisée avec ruby, vous pouvez changer:
tinyint([0-9]*)
à:
sed 's/ tinyint(1*) / boolean/g ' |
sed 's/ tinyint([0|2-9]*) / integer /g' |
hélas, cela ne fonctionne qu'à moitié parce que même si vous insérez des 1 et des 0 dans un champ booléen marqué, sqlite3 les stocke comme des 1 et des 0 de sorte que vous devez passer et faire quelque chose comme:
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)
mais il était utile d'avoir le fichier sql à regarder pour trouver toutes les opérations booléennes.
au moins, avec mysql 5.0.x, j'ai dû supprimer collate utf8_unicode_ci du dump de mysql avant de l'importer dans sqlite3. J'ai donc modifié le script pour inclure ce qui suit à la liste des seds:
sed 's/ collate utf8_unicode_ci/ /g' |
mise à jour:
MySQL traite les champs booléens comme " tinyint (1)", donc j'ai dû ajouter le suivant avant tinyint([0-9]*)
sed:
sed 's/ tinyint(1) / boolean /g' |
aussi, puisque j'essaie de répliquer un db mysql (production) à un db sqlite3 (développement) d'une application Ruby on Rails, j'ai dû ajouter la ligne suivante afin de définir une clé primaire auto-incrémentée:
sed 's/) NOT NULL/) PRIMARY KEY AUTOINCREMENT NOT NULL/g' |
je suis toujours en train d'essayer de trouver un moyen de changer la clé entrées de mysql à son correspondant créer L'INDEX entrée de sqlite3.
pour convertir les bases de données avec des BLOBs dedans j'ai ajouté --hex-blob à la commande mysqldump et le suivant à la liste de seds pipelined: -
sed -e "s/,0x\([0-9A-Z]*\),/,X'\L',/g" |
remplace les chaînes de dump HEX mysql par exemple 0x010A.... avec X'010A... ' pour importer avec sqlite.
C'est le meilleur script shell écrit et bien documenté pour convertir ssql en .db
https://gist.github.com/esperlu/943776
ou une meilleure utilisation de cet outils, C'est incroyable et rapide ESF Database Migration Toolkit .
après avoir essayé tout le script ici, il n'a pas fonctionné jusqu'à ce que j'ai utilisé l'outil esf .
Note :
Trial version add a 'T' to the begingn of each text value you have But the pro version worked like a charm :)
fonctionne très bien sur Centos 5.3 64bit. une fois que vous avez le fichier de sortie le charger comme ceci:
shell> sqlite3 file_name.DB Version 3.3.6 de SQLite Entrer." aide" pour les instructions sqlite> .les bases de données seq nom de fichier
0 principal /current_directory/nom_fichier.db
sqlite > select * de la table;
.
.
.
.
.
résultat...
sqlite>.quitter