नहीं, एक बयान में नहीं।
उन सभी तालिकाओं के नाम प्राप्त करने के लिए जिनमें Foo
. नामक कॉलम है :
SELECT table_schema, table_name
FROM information_schema.columns
WHERE column_name = 'Foo'
फिर, आपको प्रत्येक तालिका के लिए एक अद्यतन विवरण की आवश्यकता होगी। (एक ही स्टेटमेंट में कई टेबल अपडेट करना संभव है, लेकिन इसके लिए एक (अनावश्यक) क्रॉस जॉइन करना होगा।) प्रत्येक टेबल को अलग से करना बेहतर है।
आप एक MySQL संग्रहीत प्रोग्राम (जैसे प्रक्रिया) में अद्यतन विवरण निष्पादित करने के लिए गतिशील SQL का उपयोग कर सकते हैं
DECLARE sql VARCHAR(2000);
SET sql = 'UPDATE db.tbl SET Foo = 0';
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE stmt;
यदि आप info_schema.tables से चयन के लिए एक कर्सर घोषित करते हैं, तो आप एक गतिशील UPDATE
को संसाधित करने के लिए कर्सर लूप का उपयोग कर सकते हैं। प्रत्येक तालिका_नाम के लिए विवरण लौटाया गया।
DECLARE done TINYINT(1) DEFAULT FALSE;
DECLARE sql VARCHAR(2000);
DECLARE csr FOR
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns c
WHERE c.column_name = 'Foo'
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN csr;
do_foo: LOOP
FETCH csr INTO sql;
IF done THEN
LEAVE do_foo;
END IF;
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP do_foo;
CLOSE csr;
(यह सिर्फ एक उदाहरण की एक मोटा रूपरेखा है, सिंटैक्स की जाँच या परीक्षण नहीं किया गया है।)
अनुसरण करें
कुछ विचारों के बारे में कुछ संक्षिप्त टिप्पणियाँ जिन्हें शायद ऊपर दिए गए उत्तर में स्पष्ट किया गया था।
कॉलम वाले टेबल के नाम प्राप्त करने के लिए Foo
, हम information_schema.columns
. से एक क्वेरी चला सकते हैं मेज़। (यह MySQL information_schema
. में प्रदान की गई तालिकाओं में से एक है डेटाबेस।)
क्योंकि हमारे पास कई डेटाबेस में टेबल हो सकते हैं, टेबल_नाम एक टेबल की पहचान करने के लिए पर्याप्त नहीं है; हमें यह जानने की जरूरत है कि तालिका किस डेटाबेस में है। " डीबी का उपयोग करें
के साथ मिलकर काम करने के बजाय " स्टेटमेंट चलाने से पहले हम UPDATE
, हम केवल तालिका का संदर्भ दे सकते हैं UPDATE db.mytable SET Foo...
।
हम information_schema.columns
. की अपनी क्वेरी का उपयोग कर सकते हैं आगे बढ़ने के लिए और एक साथ स्ट्रिंग करने के लिए (सम्मिलित करें) भागों को हमें एक अद्यतन विवरण के लिए बनाने की आवश्यकता है, और चयन को वास्तविक विवरण वापस करने के लिए हमें कॉलम फू
अपडेट करने के लिए चलाने की आवश्यकता होगी , मूल रूप से यह:
UPDATE `mydatabase`.`mytable` SET `Foo` = 0
लेकिन हम table_schema
. से मानों में स्थानापन्न करना चाहते हैं और table_name
mydatabase
. के स्थान पर और mytable
. अगर हम इसे चलाते हैं SELECT
SELECT 'UPDATE `mydatabase`.`mytable` SET `Foo` = 0' AS sql
यह हमें एक एकल पंक्ति देता है, जिसमें एक एकल स्तंभ होता है (स्तंभ का नाम sql
. होता है , लेकिन कॉलम का नाम हमारे लिए महत्वपूर्ण नहीं है)। कॉलम का मान सिर्फ एक स्ट्रिंग होगा। लेकिन हम जो स्ट्रिंग वापस प्राप्त करते हैं वह एक SQL कथन होता है जिसे हम चला सकते हैं।
हमें वही चीज़ मिलेगी यदि हम उस स्ट्रिंग को टुकड़ों में तोड़ दें, और CONCAT का उपयोग हमारे लिए उन्हें वापस एक साथ स्ट्रिंग करने के लिए करें, उदा.
SELECT CONCAT('UPDATE `','mydatabase','`.`','mytable','` SET `Foo` = 0') AS sql
हम उस क्वेरी का उपयोग उस कथन के लिए एक मॉडल के रूप में कर सकते हैं जिसे हम information_schema.columns
के विरुद्ध चलाना चाहते हैं . हम 'mydatabase'
. को बदल देंगे और 'mytable'
information_schema.columns
. से कॉलम के संदर्भ में तालिका जो हमें डेटाबेस और तालिका_नाम देती है।
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns
WHERE c.column_name = 'Foo'
कुछ डेटाबेस ऐसे हैं जो हम निश्चित रूप से नहीं करते हैं अपडेट करना चाहते हैं... mysql
, सूचना_स्कीमा
, performance_schema
. हमें या तो उन डेटाबेसों की श्वेतसूची की आवश्यकता है जिनमें वह तालिका है जिसे हम अद्यतन करना चाहते हैं
AND c.table_schema IN ('mydatabase','anotherdatabase')
-या - हमें उन डेटाबेस को ब्लैकलिस्ट करना होगा जिन्हें हम निश्चित रूप से अपडेट नहीं करना चाहते हैं
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema')
हम उस क्वेरी को चला सकते हैं (हम ORDER BY
. जोड़ सकते हैं) यदि हम चाहते हैं कि पंक्तियाँ किसी विशेष क्रम में वापस आ जाएँ) और हमें जो वापस मिलता है वह उन कथनों की सूची है जिन्हें हम चलाना चाहते हैं। यदि हमने स्ट्रिंग्स के उस सेट को एक सादे टेक्स्ट फ़ाइल (हेडर पंक्ति और अतिरिक्त स्वरूपण को छोड़कर) के रूप में सहेजा है, तो प्रत्येक पंक्ति के अंत में एक अर्धविराम जोड़कर, हमारे पास एक फ़ाइल होगी जिसे हम mysql>
कमांड लाइन क्लाइंट।
(यदि उपरोक्त में से कोई भी भ्रमित करने वाला है, तो मुझे बताएं।)
अगला भाग थोड़ा और जटिल है। इसका शेष भाग SELECT से आउटपुट को एक सादे टेक्स्ट फ़ाइल के रूप में सहेजने के विकल्प से संबंधित है, और mysql
से कथनों को निष्पादित करता है। कमांड लाइन क्लाइंट।
MySQL एक सुविधा/सुविधा प्रदान करता है जो हमें मूल रूप से किसी भी . को निष्पादित करने की अनुमति देता है एक SQL कथन के रूप में स्ट्रिंग, एक MySQL संग्रहीत प्रोग्राम के संदर्भ में (उदाहरण के लिए, एक संग्रहीत कार्यविधि। जिस सुविधा का हम उपयोग करने जा रहे हैं उसे गतिशील SQL कहा जाता है। ।
डायनामिक SQL का उपयोग करने के लिए , हम कथनों का उपयोग करते हैं PREPARE
, निष्पादित करें
और DEALLOCATE PREPARE
. (डिलोकेट सख्ती से जरूरी नहीं है, अगर हम इसका इस्तेमाल नहीं करते हैं तो MySQL हमारे लिए सफाई करेगा, लेकिन मुझे लगता है कि इसे वैसे भी करना अच्छा अभ्यास है।)
फिर से, गतिशील SQL उपलब्ध है केवल एक MySQL संग्रहीत प्रोग्राम के संदर्भ में। ऐसा करने के लिए, हमारे पास एक स्ट्रिंग होनी चाहिए जिसमें SQL कथन है जिसे हम निष्पादित करना चाहते हैं। एक साधारण उदाहरण के रूप में, मान लें कि हमारे पास यह था:
DECLARE str VARCHAR(2000);
SET str = 'UPDATE mytable SET mycol = 0 WHERE mycol < 0';
str
. की सामग्री प्राप्त करने के लिए मूल्यांकन और एक SQL कथन के रूप में क्रियान्वित, मूल रूपरेखा है:
PREPARE stmt FROM str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
अगला जटिल हिस्सा यह है कि क्वेरी के साथ हम स्ट्रिंग मान प्राप्त करने के लिए चल रहे हैं जिसे हम SQL कथन के रूप में निष्पादित करना चाहते हैं। ऐसा करने के लिए, हम एक कर्सर लूप को एक साथ रखते हैं। उसके लिए मूल रूपरेखा हमारा SELECT स्टेटमेंट लेना है:
SELECT bah FROM humbug
और इसे एक कर्सर परिभाषा में बदल दें:
DECLARE mycursor FOR SELECT bah FROM humbug ;
हम जो चाहते हैं उसे निष्पादित करें और पंक्तियों के माध्यम से लूप करें। कथन निष्पादित करने और परिणाम सेट तैयार करने के लिए, हम कर्सर को "खोलते हैं"
OPEN mycursor;
जब हम इसके साथ समाप्त कर लेते हैं, तो हम परिणामसेट जारी करने के लिए "क्लोज़" जारी करने जा रहे हैं, इसलिए MySQL सर्वर जानता है कि हमें अब इसकी आवश्यकता नहीं है, और सफाई कर सकते हैं, और इसके लिए आवंटित संसाधनों को मुक्त कर सकते हैं।
CLOSE mycursor;
लेकिन, इससे पहले कि हम कर्सर को बंद करें, हम परिणामसेट के माध्यम से "लूप" करना चाहते हैं, प्रत्येक पंक्ति को लाते हैं, और पंक्ति के साथ कुछ करते हैं। परिणामसेट से अगली पंक्ति को एक प्रक्रिया चर में प्राप्त करने के लिए हम जिस कथन का उपयोग करते हैं वह है:
FETCH mycursor INTO some_variable;
इससे पहले कि हम पंक्तियों को वेरिएबल में ला सकें, हमें वेरिएबल को परिभाषित करने की आवश्यकता है, उदा.
DECLARE some_variable VARCHAR(2000);
चूंकि हमारा कर्सर (सेलेक्ट स्टेटमेंट) केवल एक कॉलम लौटा रहा है, हमें केवल एक वेरिएबल की जरूरत है। यदि हमारे पास अधिक कॉलम होते, तो हमें प्रत्येक कॉलम के लिए एक वेरिएबल की आवश्यकता होती।
आखिरकार, हम परिणाम सेट से अंतिम पंक्ति प्राप्त करेंगे। जब हम अगले एक को लाने का प्रयास करते हैं, तो MySQL एक त्रुटि देने वाला है।
अन्य प्रोग्रामिंग भाषाएं हमें केवल जबकि
करने देती हैं लूप, और जब हम उन सभी को संसाधित कर लेते हैं, तो हम पंक्तियों को लाते हैं और लूप से बाहर निकलते हैं। MySQL अधिक रहस्यमय है। एक लूप करने के लिए:
mylabel: LOOP
-- do something
END LOOP mylabel;
यह अपने आप में एक बहुत अच्छा अनंत लूप बनाता है, क्योंकि उस लूप में "निकास" नहीं होता है। सौभाग्य से, MySQL हमें LEAVE
देता है लूप से बाहर निकलने के तरीके के रूप में कथन। हम आम तौर पर पहली बार लूप में प्रवेश करने पर बाहर नहीं निकलना चाहते हैं, इसलिए आमतौर पर कुछ सशर्त परीक्षण होते हैं जिनका उपयोग हम यह निर्धारित करने के लिए करते हैं कि क्या हम कर चुके हैं, और लूप से बाहर निकल जाना चाहिए, या हम काम नहीं कर रहे हैं, और चारों ओर जाना चाहिए लूप फिर से।
mylabel: LOOP
-- do something useful
IF some_condition THEN
LEAVE mylabel;
END IF;
END LOOP mylabel;
हमारे मामले में, हम परिणामसेट में सभी पंक्तियों के माध्यम से लूप करना चाहते हैं, इसलिए हम एक FETCH
डालने जा रहे हैं लूप के अंदर पहला कथन (कुछ उपयोगी जो हम करना चाहते हैं)।
जब हम परिणाम सेट में अंतिम पंक्ति को पार करने का प्रयास करते हैं, तो MySQL द्वारा फेंकी गई त्रुटि और सशर्त परीक्षण के बीच एक संबंध प्राप्त करने के लिए हमें यह निर्धारित करना होगा कि क्या हमें छोड़ना चाहिए...
MySQL हमें CONTINUE HANDLER
. को परिभाषित करने का एक तरीका प्रदान करता है (कुछ कथन जो हम करना चाहते हैं) जब त्रुटि फेंकी जाती है...
DECLARE CONTINUE HANDLER FOR NOT FOUND
हम जो क्रिया करना चाहते हैं वह एक चर को TRUE पर सेट करना है।
SET done = TRUE;
इससे पहले कि हम SET चला सकें, हमें वेरिएबल को परिभाषित करना होगा:
DECLARE done TINYINT(1) DEFAULT FALSE;
इसके साथ, हम अपने LOOP को यह जांचने के लिए बदल सकते हैं कि किया गया
वेरिएबल TRUE पर सेट है, एग्जिट कंडीशन के रूप में, इसलिए हमारा लूप कुछ इस तरह दिखता है:
mylabel: LOOP
FETCH mycursor INTO some_variable;
IF done THEN
LEAVE mylabel;
END IF;
-- do something with the row
END LOOP mylabel;
"पंक्ति के साथ कुछ करें" वह जगह है जहाँ हम some_variable
. की सामग्री लेना चाहते हैं और इसके साथ कुछ उपयोगी करें। हमारा कर्सर हमें एक स्ट्रिंग लौटा रहा है जिसे हम SQL स्टेटमेंट के रूप में निष्पादित करना चाहते हैं। और MySQL हमें डायनेमिक SQL देता है ऐसा करने के लिए हम जिस सुविधा का उपयोग कर सकते हैं।
नोट:MySQL में प्रक्रिया में कथनों के क्रम के बारे में नियम हैं। उदाहरण के लिए DECLARE
शुरुआत में बयान आना होगा। और मुझे लगता है कि कंटिन्यू हैंडलर को अंतिम घोषित किया जाना चाहिए।
दोबारा:कर्सर और गतिशील SQL सुविधाएं उपलब्ध हैं केवल एक MySQL संग्रहीत प्रोग्राम के संदर्भ में, जैसे कि एक संग्रहीत कार्यविधि। मैंने ऊपर जो उदाहरण दिया वह केवल बॉडी . का उदाहरण था एक प्रक्रिया का।
इसे एक संग्रहित प्रक्रिया के रूप में बनाने के लिए, इसे कुछ इस तरह के हिस्से के रूप में शामिल करने की आवश्यकता होगी:
DELIMITER $$
DROP PROCEDURE IF EXISTS myproc $$
CREATE PROCEDURE myproc
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
-- procedure body goes here
END$$
DELIMITER ;
उम्मीद है, यह मेरे द्वारा दिए गए उदाहरण को थोड़ा और विस्तार से बताता है।