web-dev-qa-db-fra.com

Est-il possible de mysqldump un sous-ensemble d'une base de données nécessaire pour reproduire une requête?

Contexte

Je voudrais fournir le sous-ensemble de ma base de données requis pour reproduire une requête select. Mon objectif est de rendre mon workflow informatique reproductible (comme dans recherche reproductible ).

Question

Existe-t-il un moyen d'intégrer cette instruction select dans un script qui transfère les données interrogées dans une nouvelle base de données, de sorte que la base de données puisse être installée sur un nouveau serveur mysql, et l'instruction fonctionnerait avec la nouvelle base de données. La nouvelle base de données ne doit pas contenir d'enregistrements en plus de ceux qui ont été utilisés dans la requête.

Mise à jour: Pour plus de précision, je ne suis pas intéressé par un vidage csv des résultats de la requête. Ce que je dois être en mesure de faire est de vider le sous-ensemble de base de données afin qu'il puisse être installé sur une autre machine, puis la requête elle-même peut être reproductible (et modifiable par rapport au même ensemble de données).

Exemple

Par exemple, mon analyse peut interroger un sous-ensemble de données qui nécessite des enregistrements de plusieurs tables (dans cet exemple 3):

select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 
38
David LeBauer

mysqldump a l'option - where pour exécuter une clause WHERE pour une table donnée.

Bien qu'il ne soit pas possible de masquer une requête de jointure, vous pouvez exporter des lignes spécifiques de chaque table afin que chaque ligne extraite de chaque table soit impliquée ultérieurement dans la jointure.

Pour votre requête donnée, vous auriez besoin de mysqldump trois fois:

Premièrement, mysqldump toutes les lignes de table3 avec le nom ('fee', 'fi', 'fo', 'fum'):

mysqldump -u... -p... --where="name in ('fee','fi','fo','fum')" mydb table3 > table3.sql

Ensuite, mysqldump toutes les lignes de table2 qui ont des valeurs de table3_id correspondantes du premier mysqldump:

mysqldump -u... -p... --lock-all-tables --where="table3_id in (select id from table3 where name in ('fee','fi','fo','fum'))" mydb table2 > table2.sql

Ensuite, mysqldump toutes les lignes de table1 qui ont des valeurs table1_id correspondantes du deuxième mysqldump:

mysqldump -u... -p... --lock-all-tables --where="id in (select table1_id from table2 where table3_id in (select id from table3 where name in ('fee','fi','fo','fum')))" mydb table1 > table1.sql

Remarque: Étant donné que les deuxième et troisième mysqldumps nécessitent l'utilisation de plusieurs tables, --lock-all-tables doit être utilisé .

Créez votre nouvelle base de données:

mysqladmin -u... -p... mysqladmin create newdb

Enfin, chargez les trois mysqldumps dans une autre base de données et essayez d'y joindre la nouvelle base de données.

mysql -u... -p... -D newdb < table1.sql
mysql -u... -p... -D newdb < table2.sql
mysql -u... -p... -D newdb < table3.sql

Dans le client mysql, exécutez votre requête de jointure

mysql> use newdb
mysql> select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 

Essaie !!!

ATTENTION: S'ils ne sont pas indexés correctement, les deuxième et troisième mysqldumps peuvent prendre une éternité !!!

Au cas où, indexez les colonnes suivantes:

ALTER TABLE table2 ADD INDEX (table1_id);
ALTER TABLE table2 ADD INDEX (table3_id);
ALTER TABLE table3 ADD INDEX (name,id);

Je suppose que id est la clé primaire de table3.

55
RolandoMySQLDBA

Je considérerais en utilisant un 'outfile' dans le cadre de votre SELECT au lieu de mysqldump pour résoudre ce problème. Vous pouvez produire n'importe quelle instruction SELECT que vous voulez, puis ajouter "INTO OUTFILE '/path/to/outfile.csv' ..." à la fin avec la configuration appropriée pour la sortie de style CSV. Ensuite, vous pouvez simplement utiliser quelque chose comme la syntaxe ' LOAD DATA INFILE ...' pour charger les données dans votre nouvel emplacement de schéma.

Par exemple, en utilisant votre SQL:

select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum')
INTO OUTFILE '/tmp/fee-fi-fo-fum.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
; 

N'oubliez pas que vous aurez besoin de suffisamment d'espace de stockage disponible sur la partition de disque cible.

7
randomx

L'utilitaire mysqldump a une option - tables qui vous permet de spécifier les tables à vider. Il vous permet de spécifier la liste des tables.

Je ne connais pas de moyen plus simple (automatisé).

6
Richard

Ce qui m'a été utile était quelque chose comme:

mysqldump -u db_user -p db_name table_name --no_create_info \
--lock-all-tables --where 'id in (SELECT tn.id FROM table_name AS tn \
JOIN related_table AS rt ON tn.related_table_id = rt.id \
WHERE rt.some_field = 1)' > data.sql

De http://krosinski.blogspot.com/2012/12/using-table-join-with-mysqldump.html

3
Ryan

Avez-vous essayé la fonction quote dans mysql?

SELECT CONCAT("insert into table4(id,level,name,levelt2) VALUES(",   quote(table1.id),   ",",    quote(table1.level),   ",",    quote(table2.name),   ",",    quote(table2.level),    ");") as q
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 

enregistrez ce qui précède, comme query.sql

cat query.sql|mysql --skip-column-names --raw > table4.sql
2
velcrow

j'ai écrit un petit script pour un problème similaire, le voici: https://github.com/digitalist/mysql_slice

include ('queryDumper.php');


$exampleQuery="select * from information_schema.columns c1 
left join information_schema.columns c2 on 1=1 limit 1";

//define credentials
$exampleMysqli = new mysqli($Host, $user, $password, $database);
$exampleResult=$exampleMysqli->query($exampleQuery);

//if  mysqlnd (native driver installed), otherwise use wrapper
$exampleData=fetchAll($exampleResult);
$exampleMeta=$exampleResult->fetch_fields();

/*
 * field content removal options
 * column name => function name in queryDumper.php, namespace QueryDumperHelpers
 * 
 * */

$forbiddenFields=array(
'password'=>'replacePassword', //change password -> md5("password")
'login'=>'replaceLogin', //change login [email protected] -> [email protected]
'comment'=>'sanitizeComment' //lorem ipsum or 
);


//get tables dump
$dump=(\queryDumper\dump($exampleData, $exampleMeta, $forbiddenFields));



$dropDatabase=true; //default false
$dropTable=true; //default false

$dbAndTablesCreationDump=\QueryDumperDatabaseAndTables\dump($exampleMysqli,$exampleMeta, $dropDatabase, $dropTable);

$databases=$dbAndTablesCreationDump['databases'];
$tables=$dbAndTablesCreationDump['tables'];
$eol=";\n\n";
echo implode($eol, $databases)."\n";
echo implode($eol, $tables).";\n";
echo "\n";

//consider using array_unique($dump) before imploding
echo implode("\n\n", $dump);
echo "\n";
?>

c'est-à-dire. vous avez cette requête :

SELECT * FROM employees.employees e1 
LEFT JOIN employees.employees e2 ON 1=1 
LIMIT 1; 

vous avez obtenu ce vidage :

DROP DATABASE `employees`;

CREATE DATABASE `employees`;
CREATE TABLE `employees` ( /* creation code */ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT IGNORE INTO `employees`.`employees` VALUES ("10001","1953-09-02","Georgi","Facello","M","1986-06-26");

INSERT IGNORE INTO `employees`.`employees` VALUES ("10001","1953-09-02","Georgi","Facello","M","1986-06-26");
1
digitalist

Dans MySQL:

SHOW CREATE TABLE table1; -- use these two create statements
SHOW CREATE TABLE table2; -- to design table4's create statement
CREATE TABLE table4( .... );
INSERT INTO table4(id,level,name,levelt2)
SELECT table1.id, table1.level, table2.name, table2.level 
   from table1 join table2 on table1.id = table2.table1_id 
   join table3 on table3.id = table2.table3_id
   where table3.name in ('fee', 'fi', 'fo', 'fum'); 

Sur la ligne de commande:

mysqldump mydb table4 |gzip > table4.sql.gz

Sur votre serveur de destination, configurez ~/.my.cnf

[client]
default-character-set=utf8

Importer sur le serveur de destination

zcat table4.sql.gz | mysql
1
velcrow