web-dev-qa-db-ja.com

クエリを再現するために必要なデータベースのサブセットをmysqldumpすることは可能ですか?

背景

selectクエリの再現に必要なデータベースのサブセットを提供したいと思います。私の目標は、計算ワークフローを再現可能にすることです(たとえば 再現可能な研究 のように)。

質問

このselectステートメントを、クエリされたデータを新しいデータベースにダンプするスクリプトに組み込んで、データベースを新しいmysqlサーバーにインストールし、ステートメントが新しいデータベースで機能するようにする方法はありますか?新しいデータベースには、クエリで使用されたレコード以外のレコードを含めないでください。

更新:明確にするために、クエリ結果のcsvダンプには興味がありません。データベースサブセットをダンプして別のマシンにインストールできるようにしてから、クエリ自体を再現可能(かつ同じデータセットに対して変更可能)にする必要があります。

たとえば、私の分析では、複数の(この例では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 には、指定されたテーブルに対してWHERE句を実行するための -where オプションがあります。

結合クエリをmysqldumpすることはできませんが、各テーブルからフェッチされたすべての行が後で結合に含まれるように、各テーブルから特定の行をエクスポートできます。

指定したクエリでは、mysqldumpを3回実行する必要があります。

最初に、mysqldumpは名前が( 'fee'、 'fi'、 'fo'、 'fum')のすべてのtable3行をダンプします。

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

次に、mysqldumpは、最初のmysqldumpから一致するtable3_id値を持つすべてのtable2行をダンプします。

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

次に、mysqldumpは、2番目のmysqldumpからの一致するtable1_id値を持つすべてのtable1行をダンプします。

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

注:2番目と3番目のmysqldumpは複数のテーブルを使用する必要があるため、-lock-all-tablesを使用する必要があります

新しいデータベースを作成します。

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

最後に、3つのmysqldumpを別のデータベースにロードし、新しいデータベースで結合を試みます。

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

Mysqlクライアントで、結合クエリを実行します

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

試してみる !!!

警告:正しくインデックスが作成されていない場合、2番目と3番目のmysqldumpに時間がかかることがあります!!!

念のため、次の列にインデックスを付けます。

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

Idがtable3の主キーであると想定します。

55
RolandoMySQLDBA

この問題を解決するには、mysqldumpの代わりに 'outfile'を使用 をSELECTの一部として検討します。任意のSELECTステートメントを作成し、CSVスタイルの出力に適切な構成を使用して、末尾に「INTO OUTFILE '/path/to/outfile.csv' ...」を追加できます。次に、「 LOAD DATA INFILE ...」構文を使用して、データを新しいスキーマの場所にロードするだけです。

たとえば、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'
; 

ターゲットディスクパーティションには十分な空き容量が必要になることに注意してください。

7
randomx

Mysqldump utilには -tablesオプション があり、ダンプするテーブルを指定できます。テーブルのリストを指定できます。

もっと簡単な(自動化された)方法は知りません。

6
Richard

私にとって便利だったのは次のようなものでした:

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

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

3
Ryan

Mysqlで quote 関数を試しましたか?

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

上記をquery.sqlとして保存します。

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

私は同様の問題のための小さなスクリプトを書きました、ここにそれがあります: 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";
?>

つまりあなたはこのクエリを持っています

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

このダンプを取得しました

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

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

コマンドライン:

mysqldump mydb table4 |gzip > table4.sql.gz

移行先サーバーで、〜/ .my.cnfを設定します

[client]
default-character-set=utf8

宛先サーバーにインポート

zcat table4.sql.gz | mysql
1
velcrow