क्या किसी क्वेरी को पुन: प्रस्तुत करने के लिए आवश्यक डेटाबेस के सबसेट को mysqldump करना संभव है?


37

पृष्ठभूमि

मैं एक selectक्वेरी को पुन: पेश करने के लिए आवश्यक अपने डेटाबेस का सबसेट प्रदान करना चाहूंगा । मेरा लक्ष्य अपने कम्प्यूटेशनल वर्कफ़्लो को प्रतिलिपि प्रस्तुत करने योग्य बनाना है (जैसा कि प्रतिलिपि प्रस्तुत करने योग्य शोध में है )।

सवाल

क्या कोई ऐसा तरीका है जो मैं इस चयनित कथन को एक स्क्रिप्ट में शामिल कर सकता हूं जो एक नए डेटाबेस में डेटा को डंप करता है, जैसे कि डेटाबेस को नए mysql सर्वर पर स्थापित किया जा सकता है, और बयान नए डेटाबेस के साथ काम करेगा। नए डेटाबेस में उन क्वेरी के अलावा रिकॉर्ड शामिल नहीं होना चाहिए जिनका उपयोग किया गया है।

अपडेट: स्पष्टीकरण के लिए, मैं क्वेरी परिणामों के सीएसवी डंप में कोई दिलचस्पी नहीं रखता हूं। डेटाबेस उपसमुच्चय को डंप करने के लिए मुझे जो करने में सक्षम होना चाहिए वह यह है कि इसे किसी अन्य मशीन पर स्थापित किया जा सकता है, और फिर क्वेरी खुद ही प्रतिलिपि प्रस्तुत करने योग्य हो सकती है (और उसी डेटासेट के संबंध में संशोधित)।

उदाहरण

उदाहरण के लिए, मेरे विश्लेषण में डेटा के एक सबसेट की क्वेरी हो सकती है जिसके लिए एकाधिक (इस उदाहरण 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'); 

ठीक है, इसलिए कोई अतिरिक्त रिकॉर्ड नहीं। क्या आप केवल क्वेरी द्वारा निर्दिष्ट कॉलम चाहते हैं?
रिचर्ड

@ रिचर्ड ने मुझे नहीं माना था कि - यह जानना अच्छा होगा कि यह कैसे करना है।
डेविड लेबॉयर

3
यह एक बहुत ही अनोखा प्रश्न है, मुझे यकीन है कि कुछ लोगों को आश्चर्य हुआ होगा और उत्तर देने की आवश्यकता होगी। इस प्रकार के प्रश्न को सार्वजनिक करने के लिए +1।
RolandoMySQLDBA

भविष्य के पाठक: स्वीकृत उत्तर के अलावा, randomx का उत्तर देखें , जो विशेष रूप से क्वेरी द्वारा आवश्यक डेटा को डंप करता है।
टूलमेकरसेव

जवाबों:


51

mysqldump है --where किसी तालिका में एक कहां खंड निष्पादित करने के लिए विकल्प।

यद्यपि यह एक सम्मिलित क्वेरी mysqldump के लिए संभव नहीं है, आप प्रत्येक तालिका से विशिष्ट पंक्तियों को निर्यात कर सकते हैं ताकि प्रत्येक तालिका से प्राप्त प्रत्येक पंक्ति बाद में शामिल होने में शामिल हो जाए।

आपकी दी गई क्वेरी के लिए, आपको तीन बार mysqldump की आवश्यकता होगी:

सबसे पहले, mysqldump सभी टेबल 3 पंक्तियों को नाम के साथ ('शुल्क', 'फाई', 'फो', 'फॉक्स'):

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

इसके बाद, mysqldump सभी तालिका 2 पंक्तियाँ जिनमें पहले mysqldump से मिलान 3_id मान हैं:

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 सभी तालिका 1 पंक्तियों में दूसरे mysqldump से मिलान तालिका 1_id मान हैं:

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

नोट: चूंकि दूसरे और तीसरे mysqldumps को एक से अधिक टेबल का उपयोग करने की आवश्यकता होती है, --lock-all-tables का उपयोग किया जाना चाहिए

अपना नया डेटाबेस बनाएँ:

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

अंत में, तीन mysqldumps को दूसरे डेटाबेस में लोड करें और वहां नए डेटाबेस में शामिल होने का प्रयास करें।

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

कोशिश तो करो !!!

चेतावनी: यदि सही ढंग से अनुक्रमित नहीं किया जाता है, तो दूसरा और तीसरा mysqldumps हमेशा के लिए ले सकता है !!!

बस मामले में, निम्नलिखित कॉलमों को अनुक्रमित करें:

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

मुझे लगता है कि आईडी टेबल 3 की प्राथमिक कुंजी है।


1
विस्तृत उदाहरण के लिए धन्यवाद! मैं --whereप्रलेखन में खंड से चूक गया ; तुम्हें पता है कि यह कैसे काम करता है के बाद मैं इसे बाहर की कोशिश करने का मौका मिलेगा।
डेविड लेबॉयर

1
+1 यह इस समस्या के लिए --tables विधि से बेहतर है। सामान्य तौर पर, मैं --tables का उपयोग कर समाप्त होता हूं, लेकिन - the- एक बहुत अच्छा विकल्प है।
रिचर्ड

जब आप एक एकल तालिका mysqldump करते हैं, तोलॉक-ऑल-टेबल का उपयोग नहीं किया जाता है। जहां खंड को एक डंप किए जाने के अलावा अन्य टेबल शामिल हैं, आपको mysqldump --lock-all-tables बताना होगा। --ॉक-ऑल-टेबल विकल्प एक या एक से अधिक डेटाबेस को डंप करने के लिए सक्रिय है, न कि एक एकल टेबल के लिए। मैंने 2nd और 3rd mysqldumps प्रदर्शन करने की कोशिश की लेकिन इसने इस बारे में शिकायत की। एक बार जब मैं मैन्युअल रूप से जारी किया गया था - ऑल-टेबल, त्रुटि चली गई और mysqldump सफल रहा। इसके अलावा, कृपया ध्यान दें कि मेरे जवाब में पहला mysqldump --lock- ऑल-टेबल नहीं है।
रोलैंडमाइसीडीडीबीए

@ रोलैंड आपकी मदद के लिए धन्यवाद। यह पूरी तरह से काम करता है
डेविड लेबॉयर

@ रोलैंडो क्षमा करें, मैंने इसे हटाने से पहले मेरी टिप्पणी / प्रश्न का उत्तर नहीं दिया था। मुझे वही त्रुटि मिल रही थी। मैनुअल को फिर से पढ़ने के बाद, मैं देखता हूं - बैल-टेबल केवल ताले की मेज को डंप किया जा रहा है। मैं उलझन में था क्योंकि --lock- ऑल-टेबल सभी डेटाबेस में सभी तालिकाओं को लॉक करता है, जो केवल एक डेटाबेस का उपयोग करते समय आवश्यक नहीं है।
डेविड लेबॉउर

7

मैं इस समस्या को हल करने के लिए mysqldump के बजाय अपने SELECT के हिस्से के रूप में एक 'आउटफाइल' का उपयोग करने पर विचार करूंगा । आप जो भी सेलेक्ट स्टेटमेंट चाहते हैं, उसका उत्पादन कर सकते हैं, फिर CSV स्टाइल आउटपुट के लिए उपयुक्त कॉन्फ़िगरेशन के साथ अंत में "INTO OUTFILE '/path/to/outfile.csv' ... जोड़ें। फिर आप डेटा को अपने नए स्कीमा स्थान में लोड करने के लिए ' लोड डेटा इनर ...' सिंटैक्स जैसे कुछ का उपयोग कर सकते हैं ।

उदाहरण के लिए, अपने 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'
; 

ध्यान रखें कि आपको लक्ष्य डिस्क विभाजन पर पर्याप्त उपलब्ध संग्रहण स्थान की आवश्यकता होगी।


मुझे यह पाताल के लिए पसंद है। आपको अभी भी स्कीमा को नए डेटाबेस में लाने की आवश्यकता होगी, लेकिन यह आसानी से कुछ अन्य ट्रिक का उपयोग करके प्राप्त किया जाता है।
रिचर्ड

मुझे यह पसंद है क्योंकि कुछ लोग बेस टेबल नहीं चाहते हैं, बस एक सीएसवी आयातित के रूप में शामिल परिणाम हो सकता है। +1 !!!
रोलैंडमाइसीडीडीबीए

@ कैंडी आपके उत्तर के लिए धन्यवाद, लेकिन मुझे नहीं लगता कि यह मेरी समस्या का हल करता है क्योंकि मैं क्वेरी परिणामों के सीएसवी डंप में कोई दिलचस्पी नहीं रखता हूं। डेटाबेस उपसमुच्चय को डंप करने के लिए मुझे जो करने में सक्षम होना चाहिए वह यह है कि इसे किसी अन्य मशीन पर स्थापित किया जा सकता है, और फिर क्वेरी खुद ही प्रतिलिपि प्रस्तुत करने योग्य हो सकती है (और उसी डेटासेट के संबंध में संशोधित)। लक्ष्य एक कम्प्यूटेशनल वर्कफ़्लो है जो प्रतिलिपि प्रस्तुत करने योग्य अनुसंधान का समर्थन करता है ।
डेविड लेबॉयर

भविष्य के पाठकों के लिए डेविड की टिप्पणी फिर से: जैसा कि रिचर्ड ने उल्लेख किया है, आपको अलग से शामिल तालिकाओं के स्कीमा को निर्यात करने की आवश्यकता है । उन स्कीमाओं को आसानी से एक नए डेटाबेस में लोड किया जा सकता है। फिर, जैसा कि randomx ने कहा है, आप Load Data Infileउस .csv को उस नए डेटाबेस में लोड करने के लिए उपयोग करते हैं। अब, क्वेरी निष्पादित की जा सकती है।
टूलमेकरसैट

मुझे बस एहसास हुआ कि इस तकनीक की सीमा, यह है कि क्वेरी आउटपुट मूल तालिकाओं के समान संगठन में नहीं है। जबकि मुझे यह दृष्टिकोण अभी भी पसंद है, मूल तालिका संरचना को फिर से बनाने के लिए: उस तालिका के लिए आवश्यक डेटा को निर्यात करने के लिए, अलग-अलग क्वेरीज़, एक टेबल पर चलाएँ।
टूलमेकरसैट

6

Mysqldump उपयोग में एक -tables विकल्प होता है, जो आपको निर्दिष्ट करता है कि कौन सी तालिकाओं को डंप करना है। यह आपको तालिकाओं की सूची निर्दिष्ट करने देता है।

मैं किसी भी आसान (स्वचालित) तरीके से नहीं जानता।


आपकी मदद के लिए धन्यवाद, लेकिन मैं केवल आवश्यक तालिकाओं को ही नहीं, बल्कि प्रत्येक तालिका की चयनित पंक्तियों को निर्यात करना चाहता हूं। मेरे पास एक स्क्रिप्ट हो सकती है जो डंप का अनुसरण करती है delete from table1 where id not in (.....);, अगर वह सबसे आसान तरीका है, जब तक स्क्रिप्ट को स्वचालित किया जा सकता है, यह आवश्यक नहीं है कि विशिष्ट उपकरण मौजूद हो।
डेविड लेबॉयर

आप एक +1 के लायक हैं क्योंकि - टेबल्स सरल होंगे और अनावश्यक डेटा को छोड़ना नए सर्वर में सिर्फ और अधिक घोड़े का काम होगा, खासकर अगर इसमें शामिल तालिकाओं में प्रत्येक 1GB से अधिक हो। अधिकांश लोग इस तरह से करने के लिए अधिक आराम का स्तर महसूस करेंगे क्योंकि यह सिर्फ कदमों के संदर्भ में समझ में आता है। मेरा जवाब सिर्फ थोड़ी योजना और थोड़ा अधिक जोखिम लेता है।
रोलैंडमाइसीडीडीबीए


2

क्या आपने 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'); 

उपरोक्त सहेजें, query.sql के रूप में

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

1

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

मैंने इसी तरह की समस्या के लिए एक छोटी स्क्रिप्ट लिखी है, यहाँ यह है: https://github.com/digitalist/mysql_sice

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 vasya@mail.ru -> vasya@example.com
'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");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.