MySQL सबक्वेरी के साथ समस्या


16

यह प्रश्न क्यों करता है

DELETE FROM test 
WHERE id = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           );

कभी 1 पंक्ति हटाएं, कभी 2 पंक्तियाँ और कभी कुछ नहीं?

अगर मैं इसे इस रूप में लिखूं:

SET @var = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY RAND() 
             LIMIT 1
           ); 
DELETE FROM test 
WHERE id=@var;

तब यह सही ढंग से काम करता है - सबक्वेरी में समस्या है?

जवाबों:


13

पहली क्वेरी लगातार काम नहीं करने का कारण यह है कि MySQL सबक्वेरी को कैसे प्रोसेस करता है। वास्तव में, उपश्रेणी पुनर्लेखन और परिवर्तनों का अनुभव करेगी

यहाँ समझाया गया चार (4) घटक हैं:

  • Item_in_optimizer
  • Item_in_subselect
  • Item_ref
  • Left_expression_Cache

पोस्ट किए गए उदाहरणों से, एक item_ref को आत्म संदर्भ बनाने की अनुमति देना असंभव होगा। आपकी एकल DELETE क्वेरी के संदर्भ में, संपूर्ण के रूप में परीक्षण तालिका पूरी तरह से स्वयं संदर्भ नहीं दे सकती क्योंकि कुछ कुंजियाँ परिवर्तन के दौरान उपलब्ध हैं और कुछ नहीं हैं। इसलिए, जब कोई क्वेरी स्व-संदर्भ करता है, तो एक कुंजी (इस मामले में आईडी) एक परिवर्तन में गायब हो सकती है, भले ही वास्तविक स्व-संदर्भित तालिका में कुंजी हो।

मिक़्क़ल सबक्वेरीज़ केवल सब-सेलेक्ट्स के लिए शानदार हैं, यहां तक ​​कि कई बार सेल्फ-रेफ़रिंग भी। गैर-चयनित प्रश्नों के लिए भी ऐसा नहीं कहा जा सकता है।

मुझे उम्मीद है कि यह स्पष्टीकरण मदद करता है।


7

मुझे लगता है कि जिस कारण से यह अपेक्षा के अनुरूप काम नहीं करता है वह यह नहीं है कि MySQL उप-प्रक्रियाओं को कैसे संसाधित करता है बल्कि MySQL कैसे UPDATEबयान करता है। बयान:

DELETE 
FROM test 
WHERE id = 
      ( SELECT id 
        FROM 
            ( SELECT * 
              FROM test
            ) temp 
        ORDER BY RAND() 
        LIMIT 1
      ) 

WHEREपंक्ति द्वारा स्थिति पंक्ति को संसाधित करेगा । मतलब, हर पंक्ति के लिए, यह सबक्वेरी चलाएगा और इसके विरुद्ध परिणाम का परीक्षण करेगा id:

  ( SELECT id 
    FROM 
        ( SELECT * 
          FROM test
        ) temp 
    ORDER BY RAND() 
    LIMIT 1
  ) 

तो, यह कभी-कभी 0, 1, 2 या उससे अधिक पंक्तियों से मेल खाता है (और हटाता है)!


आप इसे इस तरह से फिर से लिख सकते हैं और उपनगर को एक बार संसाधित किया जाएगा:

DELETE t
FROM 
      test t
  JOIN 
      ( SELECT id 
        FROM test  
        ORDER BY RAND() 
        LIMIT 1
      ) tmp
    ON tmp.id = t.id

1

इस पृष्ठ पर पहली गोली से , LIMITmysql उपवर्गों में समर्थित नहीं है। मुझे यकीन नहीं है कि यह आपके लिए एक त्रुटि क्यों नहीं फेंक रहा है, हालांकि।


2
LIMITप्रयोग करने के लिए केवल समर्थित नहीं है IN (<code> बैकटिक के साथ बदल दिया ~ drachenstern)
tomas.lang

अच्छा ... मैंने कुछ सीखा, जो बताता है कि यह त्रुटि क्यों नहीं हुई!
डेरेक डाउनी

@ tomas.lang आप <code> ब्लॉक के बजाय शब्द के आसपास `(टिक मार्क) का उपयोग कर सकते हैं।
डेरेक डाउनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.