it-swarm.it

È possibile mysqldump un sottoinsieme di un database richiesto per riprodurre una query?

Background

Vorrei fornire il sottoinsieme del mio database richiesto per riprodurre una query select. Il mio obiettivo è rendere riproducibile il mio flusso di lavoro computazionale (come in ricerca riproducibile ).

Domanda

C'è un modo in cui posso incorporare questa istruzione select in uno script che scarica i dati richiesti in un nuovo database, in modo tale che il database possa essere installato su un nuovo server mysql e che l'istruzione funzioni con il nuovo database. Il nuovo database non deve contenere record oltre a quelli utilizzati nella query.

Aggiornamento: Per chiarimenti, non sono interessato a un dump CSV dei risultati della query. Quello che devo essere in grado di fare è scaricare il sottoinsieme del database in modo che possa essere installato su un altro computer e quindi la query stessa può essere riproducibile (e modificabile rispetto allo stesso set di dati).

Esempio

Ad esempio, la mia analisi potrebbe eseguire una query su un sottoinsieme di dati che richiede record da più tabelle (in questo esempio 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 ha l'opzione - where per eseguire una clausola WHERE per una determinata tabella.

Sebbene non sia possibile eseguire il mysqldump di una query di join, è possibile esportare righe specifiche da ciascuna tabella in modo che ogni riga recuperata da ciascuna tabella venga coinvolta nel join in un secondo momento.

Per la tua specifica query, dovrai mysqldump tre volte:

Innanzitutto, mysqldump tutte le righe della tabella 3 con nome in ('fee', 'fi', 'fo', 'fum'):

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

Quindi, mysqldump tutte le righe table2 che hanno valori table3_id corrispondenti dal primo 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

Quindi, mysqldump tutte le righe table1 che hanno valori table1_id corrispondenti dal secondo 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

Nota: poiché il secondo e il terzo mysqldumps richiedono l'uso di più di una tabella, è necessario utilizzare --lock-all-tables .

Crea il tuo nuovo database:

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

Infine, carica i tre mysqldumps in un altro database e prova a unirti nel nuovo database.

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

Nel client mysql, esegui la query di join

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'); 

Provaci !!!

ATTENZIONE: se non indicizzato correttamente, il secondo e il terzo mysqldumps potrebbero richiedere per sempre !!!

Per ogni evenienza, indicizza le seguenti colonne:

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

Presumo che id sia la chiave primaria di table3.

55
RolandoMySQLDBA

Vorrei considerare sando un 'outfile' come parte di SELECT invece di mysqldump per risolvere questo problema. È possibile produrre qualsiasi istruzione SELECT desiderata, quindi aggiungere "INTO OUTFILE '/path/to/outfile.csv' ..." alla fine con la configurazione appropriata per l'output in stile CSV. Quindi puoi semplicemente usare qualcosa come la sintassi ' LOAD DATA INFILE ...' per caricare i dati nella nuova posizione del tuo schema.

Ad esempio, usando il tuo 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'
; 

Tieni presente che avrai bisogno di spazio di archiviazione sufficiente sulla partizione del disco di destinazione.

7
randomx

L'utilità mysqldump ha un'opzione - tables che ti permette di specificare quali tabelle scaricare. Ti consente di specificare l'elenco delle tabelle.

Non conosco alcun modo più semplice (automatizzato).

6
Richard

Ciò che è stato utile per me è stato qualcosa di simile:

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

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

3
Ryan

Hai provato la funzione quote in 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'); 

salvare quanto sopra, come query.sql

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

ho scritto una piccola sceneggiatura per un problema simile, eccola qui: 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";
?>

cioè. hai questa query :

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

hai ottenuto questo dump :

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

In 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'); 

Sulla riga di comando:

mysqldump mydb table4 |gzip > table4.sql.gz

Sul tuo server di destinazione, imposta ~/.my.cnf

[client]
default-character-set=utf8

Importa sul server di destinazione

zcat table4.sql.gz | mysql
1
velcrow