it-swarm.com.de

Ist es möglich, eine Teilmenge einer Datenbank zu mysqldump, die zum Reproduzieren einer Abfrage erforderlich ist?

Hintergrund

Ich möchte die Teilmenge meiner Datenbank bereitstellen, die zum Reproduzieren einer select - Abfrage erforderlich ist. Mein Ziel ist es, meinen Rechenworkflow reproduzierbar zu machen (wie in reproduzierbare Forschung ).

Frage

Gibt es eine Möglichkeit, diese select-Anweisung in ein Skript zu integrieren, das die abgefragten Daten in eine neue Datenbank speichert, sodass die Datenbank auf einem neuen MySQL-Server installiert werden kann und die Anweisung mit der neuen Datenbank funktioniert. Die neue Datenbank sollte keine zusätzlichen Datensätze enthalten, die in der Abfrage verwendet wurden.

Update : Zur Verdeutlichung bin ich nicht an einem CSV-Dump mit Abfrageergebnissen interessiert. Was ich tun muss, ist, die Datenbank-Teilmenge zu sichern, damit sie auf einem anderen Computer installiert werden kann, und dann kann die Abfrage selbst reproduzierbar (und in Bezug auf denselben Datensatz modifizierbar) werden.

Beispiel

Beispielsweise könnte meine Analyse eine Teilmenge von Daten abfragen, für die Datensätze aus mehreren (in diesem Beispiel 3) Tabellen erforderlich sind:

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 hat die Option - where , um eine WHERE-Klausel für eine bestimmte Tabelle auszuführen.

Obwohl es nicht möglich ist, eine Join-Abfrage zu mysqldumpen, können Sie bestimmte Zeilen aus jeder Tabelle exportieren, sodass jede aus jeder Tabelle abgerufene Zeile später in den Join einbezogen wird.

Für Ihre angegebene Abfrage müssten Sie dreimal mysqldump ausführen:

Zuerst mysqldump alle table3-Zeilen mit dem Namen in ('fee', 'fi', 'fo', 'fum'):

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

Als nächstes mysqldump alle table2-Zeilen mit übereinstimmenden table3_id-Werten aus dem ersten 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

Dann mysqldump alle table1-Zeilen, die übereinstimmende table1_id-Werte aus dem zweiten mysqldump haben:

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

Hinweis: Da für den zweiten und dritten mysqldumps mehr als eine Tabelle verwendet werden muss, muss --lock-all-tables verwendet werden .

Erstellen Sie Ihre neue Datenbank:

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

Laden Sie abschließend die drei mysqldumps in eine andere Datenbank und versuchen Sie dort den Join in der neuen Datenbank.

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

Führen Sie im MySQL-Client Ihre Join-Abfrage aus

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

Versuche es !!!

WARNUNG: Wenn nicht richtig indiziert, können die zweiten und dritten mysqldumps ewig dauern !!!

Indizieren Sie für alle Fälle die folgenden Spalten:

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

Ich gehe davon aus, dass id der Primärschlüssel von table3 ist.

55
RolandoMySQLDBA

Ich würde nter Verwendung einer 'Outfile' als Teil Ihres SELECT anstelle von mysqldump in Betracht ziehen, um dieses Problem zu lösen. Sie können eine beliebige SELECT-Anweisung erstellen und am Ende "INTO OUTFILE '/path/to/outfile.csv' ..." mit der entsprechenden Konfiguration für die Ausgabe im CSV-Stil anhängen. Dann können Sie einfach die Syntax ' LOAD DATA INFILE ...' verwenden, um die Daten in Ihren neuen Schema-Speicherort zu laden.

Verwenden Sie beispielsweise 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'
; 

Beachten Sie, dass Sie genügend verfügbaren Speicherplatz auf der Zielfestplattenpartition benötigen.

7
randomx

Das mysqldump-Dienstprogramm verfügt über eine - tables-Option , mit der Sie angeben können, welche Tabellen ausgegeben werden sollen. Hier können Sie die Liste der Tabellen angeben.

Ich kenne keinen einfacheren (automatisierten) Weg.

6
Richard

Was für mich nützlich war, war so etwas wie:

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

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

3
Ryan

Haben Sie die Funktion quote in MySQL ausprobiert?

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

speichern Sie das oben genannte als query.sql

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

ich habe ein kleines Skript für ein ähnliches Problem geschrieben, hier ist es: 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";
?>

d.h. Sie haben diese Abfrage :

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

Du hast diesen 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'); 

In der Befehlszeile:

mysqldump mydb table4 |gzip > table4.sql.gz

Richten Sie auf Ihrem Zielserver ~/.my.cnf ein

[client]
default-character-set=utf8

Auf Zielserver importieren

zcat table4.sql.gz | mysql
1
velcrow