MySQL HAVING को SELECT उपनाम का उपयोग करने की अनुमति क्यों देता है?


14

SQL में, जहाँ तक मुझे पता है, लॉजिकल क्वेरी प्रोसेसिंग ऑर्डर, जो कि वैचारिक व्याख्या क्रम है, निम्न तरीके से FROM से शुरू होता है:

  1. से
  2. कहाँ पे
  3. समूह द्वारा
  4. होने
  5. चुनते हैं
  6. द्वारा आदेश

इस सूची के बाद यह देखना आसान है कि आप WHERE क्‍लॉज में सेलेक्‍ट अलायस क्‍यों नहीं रख सकते, क्‍योंकि उपनाम अभी तक नहीं बनाया गया है। T-SQL (SQL Server) इसका सख्ती से पालन करता है और जब तक आपने SELECT पास नहीं किया है तब तक आप SELECT उपनाम का उपयोग नहीं कर सकते हैं।

लेकिन MySQL में यह संभव है कि सेलेक्ट अलायसेस का उपयोग HAVING क्लॉज में किया जाए, भले ही इसे (तार्किक रूप से) SELECT क्लॉज से पहले संसाधित किया जाए। ऐसा कैसे हो सकता है?

एक उदाहरण देने के लिए:

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;

टी-एसक्यूएल में बयान अमान्य है (क्योंकि हवलिंग सेलेक्ट अलियास का जिक्र है Amount) ...

Msg 207, Level 16, State 1, Line 5
Invalid column name 'Amount'.

... लेकिन MySQL में ठीक काम करता है।

इसके आधार पर, मैं सोच रहा हूँ:

  • क्या MySQL उपयोगकर्ता की मदद के लिए SQL नियमों में एक शॉर्टकट ले रहा है? शायद किसी तरह के पूर्व-विश्लेषण का उपयोग कर रहे हैं?
  • या फिर MySQL एक अलग वैचारिक व्याख्या क्रम का उपयोग कर रहा है जो कि मैं सभी RDBMS का पालन कर रहा था?

1
मेरा अनुमान है, यह आपका दूसरा बुलेट पॉइंट है।
a_horse_with_no_name

3
वैसे मुझे लगता है कि यह किसी भी अस्पष्टता या भ्रम का कारण नहीं बनता है जब तक कि वे रैंकिंग कार्यों का समर्थन नहीं करते हैं। तब SELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1के रूप में समस्याग्रस्त हो जाएगा ROW_NUMBERरन के बादHAVING
मार्टिन स्मिथ

मुझे यकीन नहीं है कि MySQL द्वारा समर्थित रैंकिंग कार्य क्या हैं। आप पंक्ति संख्या चाहते हैं तो आप इस तरह से इसे बनाने के लिए है: SELECT @rownum:=@rownum + 1 as row ...। शायद यही कारण है कि वे सिलेक्ट अलायसेस का समर्थन सिर्फ इसलिए करते हैं क्योंकि वे इस तथ्य के कारण कर सकते हैं कि वे उन चीजों का समर्थन नहीं करते हैं जो इसे असंभव बना देंगे ... क्या आप जानते हैं? :)
ओहलिन

जैसा कि @MartinSmith बताता है, जब तक कि कोई विंडो / रैंकिंग फ़ंक्शन नहीं हैं, तब तक HAVINGऔर SELECTक्लॉज़ के निष्पादन का तार्किक क्रम परस्पर बदला जा सकता है। तो, ऐसा करने में कोई अस्पष्टता नहीं है और जब राक्षसी भाव होते हैं तो कोड के रूप को सरल बना सकते हैं SELECT
ypercube y

उम्मीद है कि यह कुछ हद तक इस विषय पर है कि मैंने एक सवाल का जवाब दिया। यहां एक ही आउटपुट distinctsके Alias in the Havingबावजूद तेजी से परिणाम (के साथ ) का आनंद ले रहा है Explain। इसलिए ऑप्टिमाइज़र के साथ कुछ बदलाव हो रहा है।
आकर्षित किया

जवाबों:


13

जब आप इस प्रकार का प्रश्न पूछते हैं तो सूचना का सबसे अच्छा स्रोत IMHO MySQL प्रलेखन है। अब बात है। यह MySql एक्सटेंशन का व्यवहार है GROUP BYजो डिफ़ॉल्ट रूप से सक्षम है।

MySQL द्वारा ग्रुप में MySQL एक्सटेंशन्स
इस व्यवहार को एग्रीगेटेड कॉलम के लिए HAVING क्लॉज में एक अन्य के उपयोग की अनुमति देता है

यदि आप मानक व्यवहार चाहते हैं, तो आप इस एक्सटेंशन को अक्षम कर सकते हैं sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

यदि आप ONLY_FULL_GROUP_BYsql_mode में उपर्युक्त क्वेरी को निष्पादित करने का प्रयास करते हैं, तो आपको निम्न त्रुटि संदेश मिलेगा:

गैर-समूहीकरण फ़ील्ड 'राशि' का उपयोग HAVING क्लॉज में किया जाता है: चयन YEAR (ऑर्डर करें), COUNT (*) के रूप में YEAR से ऑर्डर ग्रुप से राशि (ऑर्डर) HAVING राशि> 1

यहाँ SQLFiddle डेमो है

इसलिए यह आप पर निर्भर है कि आप MySQL के अपने उदाहरण को कैसे कॉन्फ़िगर और उपयोग कर सकते हैं।


आप दस्तावेज़ के बारे में बिल्कुल सही हैं। मैंने कभी नहीं सोचा था कि यह इतना स्पष्ट रूप से लिखा जा सकता है जैसा कि आपने इसे ऊपर उद्धृत किया है :) इसे खोजने के लिए धन्यवाद ...
ओहलिन

इस उत्तर का उत्तर नहीं है "क्या MySQL पूर्व-विश्लेषण कर रहा है या MySQL एक अलग वैचारिक व्याख्या का उपयोग कर रहा है?"।
पचेरियर

2
@Pacerier MySQL निश्चित रूप से "पूर्व-विश्लेषण कर रहा है", क्योंकि क्वेरी ऑप्टिमाइज़र क्वेरी के सभी पहलुओं पर विचार करता है, जबकि यह मानता है कि यह सबसे अच्छा क्वेरी प्लान होगा। एक "अलग वैचारिक व्याख्या" की धारणा इस तथ्य की गलतफहमी है कि सर्वर किसी भी तरह से वैचारिक मॉडल को लागू करने के लिए स्वतंत्र है जो एक वैध परिणाम पैदा करता है। ORDER BY, उदाहरण के लिए, वास्तव में यह सैद्धांतिक रूप से पहले की तुलना में बहुत अधिक संभाला जा सकता है, अगर ऑप्टिमाइज़र पाता है कि पंक्तियों को शुरू में एक सूचकांक से पढ़ा जा सकता है जो पहले से ही वांछित क्रम में है।
माइकल - साइक्लबोट

4

अच्छा प्रश्न।

मुझे लगता है कि आपको इन क्वेरी को चलाना चाहिए

EXPLAIN SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;
SHOW WARNINGS;

और जांच करें कि क्वेरी फिर से कैसे लिखी गई है। मुझे पूरा यकीन है कि क्वेरी ऑप्टिमाइज़र COUNT (*) के साथ राशि को प्रतिस्थापित करता है

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING COUNT(*)>1;

जैसे यह साथ देता है

select 
 *
from 
 test
where 
 id = 5 - 3

क्वेरी ऑप्टिमाइज़र के बाद कुछ इस तरह से।

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.