मैं किसी तालिका की सभी पंक्तियों के माध्यम से कैसे लूप कर सकता हूं? (माई एसक्यूएल)


90

मेरे पास एक तालिका ए है और एक प्राथमिक कुंजी आईडी है।

अब मैं ए में सभी पंक्तियों से गुजरना चाहता हूं।

मुझे 'ए में प्रत्येक रिकॉर्ड के लिए' जैसा कुछ मिला, लेकिन ऐसा लगता है कि आप इसे MySQL में कैसे नहीं करते हैं।

बात यह है कि प्रत्येक पंक्ति के लिए मैं एक फ़ील्ड लेना चाहता हूँ और इसे बदलना चाहता हूँ, इसे किसी अन्य तालिका में सम्मिलित करता हूँ और फिर पंक्ति के कुछ क्षेत्रों को अद्यतन करता हूँ। मैं एक बयान में चुनिंदा भाग और सम्मिलित कर सकता हूं, लेकिन मुझे नहीं पता कि अपडेट कैसे प्राप्त किया जाए। इसलिए मैं लूप करना चाहता हूं। और अभ्यास के लिए मैं MySQL के अलावा किसी और चीज का उपयोग नहीं करना चाहता।

संपादित करें

मैं एक उदाहरण की सराहना करूंगा।

और एक समाधान जिसे एक प्रक्रिया में डालने की आवश्यकता नहीं है।

संपादित करें २

ठीक है इस परिदृश्य के बारे में सोचो:

तालिका A और B, प्रत्येक फ़ील्ड ID और VAL के साथ।

अब यह छद्म कोड है जो मैं करना चाहता हूं:

for(each row in A as rowA)
{
  insert into B(ID, VAL) values(rowA[ID], rowA[VAL]);
}

मूलतः एक लूप का उपयोग करके ए में बी की सामग्री की नकल करना।

(यह सिर्फ एक सरलीकृत उदाहरण है, निश्चित रूप से आप इसके लिए लूप का उपयोग नहीं करेंगे।)}


हाय रफील मेरे लिए इसकी त्रुटि के रूप में: मेरी SQL> के लिए (प्रत्येक पंक्ति में wp_mobiune_ecommune_user x) {wp_mobiune_ecommune_user (लिंग_न्यू) मान (x [लिंग])} में डालें; आरआरओआर 1064 (42000): आपके एसक्यूएल सिंटैक्स में एक त्रुटि है; 'के लिए (प्रत्येक पंक्ति में wp_mobiune_ecommune_user x के रूप में प्रत्येक पंक्ति) {के रूप में उपयोग करने के लिए अपने MySQL सर्वर संस्करण से मेल खाती है कि मैनुअल की जाँच करें 1 लाइन पर wp_mobiune_ecommune में सम्मिलित करें
dinesh kandpal

जवाबों:


137

चूंकि लूप का सुझाव एक प्रक्रिया प्रकार समाधान के लिए अनुरोध का अर्थ है। यह रहा मेरा।

कोई भी क्वेरी जो तालिका से लिए गए किसी एकल रिकॉर्ड पर काम करती है, उसे इस तरह से तालिका की प्रत्येक पंक्ति के माध्यम से चलाने के लिए एक प्रक्रिया में लपेटा जा सकता है:

DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;

फिर यहां आपके उदाहरण के अनुसार प्रक्रिया है (स्पष्टता के लिए इस्तेमाल की जाने वाली तालिका_ए और तालिका_)

CREATE PROCEDURE ROWPERROW()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM table_A INTO n;
SET i=0;
WHILE i<n DO 
  INSERT INTO table_B(ID, VAL) SELECT (ID, VAL) FROM table_A LIMIT i,1;
  SET i = i + 1;
END WHILE;
End;
;;

फिर सीमांकक रीसेट करने के लिए मत भूलना

DELIMITER ;

और नई प्रक्रिया चलाते हैं

CALL ROWPERROW();

आप "INSERT INTO" लाइन में जो चाहें कर सकते हैं, जिसे मैंने केवल आपके उदाहरण अनुरोध से कॉपी किया है।

ध्यान से देखें कि "इंसर्ट इन्टो" लाइन का उपयोग यहां प्रश्न में लाइन को दर्शाता है। इस उत्तर के लिए टिप्पणियों के अनुसार आपको यह सुनिश्चित करने की आवश्यकता है कि आपकी क्वेरी सिंटैक्टिक रूप से सही है जिसके लिए आप जिस एसक्यूएल का संस्करण चला रहे हैं।

साधारण मामले में जहां आपका आईडी क्षेत्र बढ़ा हुआ है और 1 पंक्ति में शुरू होता है, उदाहरण बन सकता है:

INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;

के साथ "सेलेक्ट काउंट" लाइन की जगह

SET n=10;

क्या आप केवल टेबल_ ए में पहले 10 रिकॉर्ड पर अपनी क्वेरी का परीक्षण करेंगे।

एक अंतिम बात। यह प्रक्रिया अलग-अलग तालिकाओं में घोंसला बनाने के लिए भी बहुत आसान है और एकमात्र तरीका था कि मैं एक तालिका पर एक प्रक्रिया कर सकता हूं जिसने गतिशील रूप से मूल तालिका की प्रत्येक पंक्ति से अलग-अलग संख्याओं को एक नई तालिका में डाला।

यदि आपको इसे तेजी से चलाने की आवश्यकता है, तो सुनिश्चित करें कि इसे सेट करने का प्रयास करें, यदि नहीं तो यह ठीक है। आप कर्सर के रूप में उपरोक्त को भी फिर से लिख सकते हैं लेकिन यह प्रदर्शन में सुधार नहीं कर सकता है। उदाहरण के लिए:

DROP PROCEDURE IF EXISTS cursor_ROWPERROW;
DELIMITER ;;

CREATE PROCEDURE cursor_ROWPERROW()
BEGIN
  DECLARE cursor_ID INT;
  DECLARE cursor_VAL VARCHAR;
  DECLARE done INT DEFAULT FALSE;
  DECLARE cursor_i CURSOR FOR SELECT ID,VAL FROM table_A;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
  OPEN cursor_i;
  read_loop: LOOP
    FETCH cursor_i INTO cursor_ID, cursor_VAL;
    IF done THEN
      LEAVE read_loop;
    END IF;
    INSERT INTO table_B(ID, VAL) VALUES(cursor_ID, cursor_VAL);
  END LOOP;
  CLOSE cursor_i;
END;
;;

उन चर को घोषित करने के लिए याद रखें जिन्हें आप उसी प्रकार के रूप में उपयोग करेंगे, जो कि सारणीबद्ध तालिकाओं से हैं।

मेरी सलाह है कि जब आप कर सकते हैं तब सेट किए गए प्रश्नों के साथ जाएं, और यदि आपको करना है तो केवल सरल लूप या कर्सर का उपयोग करें।


2
INSERT INTO table_B (ID, VAL) VALUES (ID, VAL) से तालिका_A सीमा 1, 1; एक सिंटैक्स त्रुटि देता है।
योनातन

1
याद आ रहा है 'DECLARE किया INT DEFAULT FALSE?' कर्सर_आई घोषणा के बाद
एरिकेल

1
संपत्ति को सही करने के लिए कहां सेट किया गया है, मुझे इसे रखना चाहिए या एक आरक्षित शब्द है जो कि mysql कर्सर द्वारा स्वचालित रूप से उपयोग किया जाता है?
इग्नाइटेकोडर्स

1
INSERT INTO कॉल SQL 5.5 के रूप में एक सिंटैक्स त्रुटि फेंकता है, सही कॉल INSERT INTO table_B है (ID, VAL) का चयन करें (ID, VAL) FROM table_A WHERE ID = i से;
अंबेर

यह एक जीवनकाल लेगा, इसलिए सीमा और वेतन वृद्धि को बदलकर बैच आकार को 1000 करने की कोशिश करें: LIMIT i,1000;और set i = i + 1000;
एलन डीप

16

आपको वास्तव में दो प्रश्नों (मूल सम्मिलित) से युक्त एक सेट आधारित समाधान का उपयोग करना चाहिए:

INSERT INTO TableB (Id2Column, Column33, Column44)
SELECT id, column1, column2 FROM TableA

UPDATE TableA SET column1 = column2 * column3

और अपने परिवर्तन के लिए:

INSERT INTO TableB (Id2Column, Column33, Column44)
SELECT 
    id, 
    column1 * column4 * 100, 
    (column2 / column12) 
FROM TableA

UPDATE TableA SET column1 = column2 * column3

अब यदि आपका रूपांतर इससे अधिक जटिल है और कई तालिकाओं को शामिल किया गया है, तो विवरण के साथ एक और प्रश्न पोस्ट करें।


उदाहरण के लिए +1। हालांकि मुझे संदेह है कि यह मेरे सीटू b / c में लागू है, बाद में अपडेट डालने से संबंधित है और विशेष रूप से चयनित पंक्तियों के कारण कौन सा विशिष्ट सम्मिलित है। यही कारण है कि मैंने एक लूप का सुझाव दिया है, इसलिए मैं व्यक्तिगत रूप से प्रत्येक पंक्ति के लिए चयन / सम्मिलित / अपडेट कर सकता हूं।
राफेल

2
@ Raffael1984: "विशिष्ट पंक्तियों के कारण विशिष्ट पंक्तियों" के लिए शर्तों को जोड़ने के लिए अपने प्रश्न को संपादित करें और हम इसके साथ मदद कर सकते हैं। आप वास्तव में कर्सर / लूप मार्ग पर नहीं जाना चाहते हैं - यह बेहद अक्षम है।
राज मोर

ओह ठीक है ... तुम्हें पता है कि मैं सेट आधारित क्वेरी रास्ते पर जाने से ज्यादा खुश हूँ! लेकिन प्रभावोत्पादकता यहाँ कोई प्रेरणा नहीं है क्योंकि मेरा प्रश्न अकादमिक रुचि से अधिक है। मेज काफी छोटा है मैं इसे हाथ से कर सकता था। मैं वास्तव में एक लूप-संस्करण की सराहना करूंगा। मैं उस समस्या को फिर से पोस्ट कर सकता हूं जो किसी व्यक्ति को सेट आधारित शैली के साथ मेरी सहायता करने के लिए अधिक विवरण प्रदान कर सकती है।
राफेल

@RajMore से सहमत हैं, कर्सर / पाश अक्षम है, नीचे दिए गए संदर्भ के लिए कर्सर प्रदर्शन के बारे में 2 लिंक हैं: 1. rpbouman.blogspot.tw/2006/09/refactoring-mysql-cursors.html 2. stackoverflow.com/questions/11549567/ ...
ब्राउन लिन

@ राजमोर क्या आप मेरे सवाल
नूरव

4

CURSORS यहां एक विकल्प हैं, लेकिन आम तौर पर उन पर भरोसा किया जाता है क्योंकि वे अक्सर क्वेरी इंजन का सबसे अच्छा उपयोग नहीं करते हैं। यह देखने के लिए कि क्या आप CURSOR का उपयोग किए बिना क्या करना चाहते हैं, हासिल कर सकते हैं, यह देखने के लिए 'SET आधारित प्रश्न' की जांच पर विचार करें।


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

0

श्रीमान पर्पल का उदाहरण जो मैंने mysql ट्रिगर में इस्तेमाल किया, जैसे कि

begin
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
Select COUNT(*) from user where deleted_at is null INTO n;
SET i=0;
WHILE i<n DO 
  INSERT INTO user_notification(notification_id,status,userId)values(new.notification_id,1,(Select userId FROM user LIMIT i,1)) ;
  SET i = i + 1;
END WHILE;
end

2
क्या आप कृपया कुछ सुझाव जोड़ सकते हैं कि आप कैसे हल करते हैं?
theTanic

-26
    Use this:

    $stmt = $user->runQuery("SELECT * FROM tbl WHERE ID=:id");
    $stmt->bindparam(":id",$id);
    $stmt->execute();

        $stmt->bindColumn("a_b",$xx);
        $stmt->bindColumn("c_d",$yy);


    while($rows = $stmt->fetch(PDO::FETCH_BOUND))
    {
        //---insert into new tble
    }   
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.