Database
 sql >> डेटाबेस >  >> RDS >> Database

टेबल एक्सप्रेशन के मूल तत्व, भाग 5 - सीटीई, तार्किक विचार

यह आलेख तालिका भावों के बारे में श्रृंखला का पाँचवाँ भाग है। भाग 1 में मैंने टेबल एक्सप्रेशन की पृष्ठभूमि प्रदान की है। भाग 2, भाग 3 और भाग 4 में, मैंने व्युत्पन्न तालिकाओं के तार्किक और अनुकूलन दोनों पहलुओं को कवर किया। इस महीने मैंने कॉमन टेबल एक्सप्रेशन (सीटीई) का कवरेज शुरू किया। व्युत्पन्न तालिकाओं की तरह, मैं पहले सीटीई के तार्किक उपचार को संबोधित करूंगा, और भविष्य में मैं अनुकूलन विचारों को प्राप्त करूंगा।

अपने उदाहरणों में मैं TSQLV5 नामक एक नमूना डेटाबेस का उपयोग करूँगा। आप उस स्क्रिप्ट को ढूंढ सकते हैं जो इसे यहां बनाता है और पॉप्युलेट करता है, और इसका ईआर आरेख यहां ।

सीटीई

आइए सामान्य तालिका व्यंजक . शब्द से प्रारंभ करें . न तो यह शब्द, न ही इसका संक्षिप्त नाम CTE, ISO/IEC SQL मानक विनिर्देशों में दिखाई देता है। तो यह हो सकता है कि यह शब्द डेटाबेस उत्पादों में से एक में उत्पन्न हुआ और बाद में कुछ अन्य डेटाबेस विक्रेताओं द्वारा अपनाया गया। आप इसे Microsoft SQL Server और Azure SQL डेटाबेस के दस्तावेज़ीकरण में पा सकते हैं। टी-एसक्यूएल इसका समर्थन करता है जो एसक्यूएल सर्वर 2005 से शुरू होता है। मानक क्वेरी एक्सप्रेशन शब्द का उपयोग करता है एक अभिव्यक्ति का प्रतिनिधित्व करने के लिए जो बाहरी क्वेरी सहित एक या अधिक सीटीई को परिभाषित करता है। यह सूची तत्व के साथ . शब्द का उपयोग करता है टी-एसक्यूएल सीटीई को क्या कहते हैं, इसका प्रतिनिधित्व करने के लिए। मैं शीघ्र ही एक क्वेरी एक्सप्रेशन के लिए सिंटैक्स प्रदान करूंगा।

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

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

सिंटैक्स

क्वेरी एक्सप्रेशन के लिए मानक का सिंटैक्स यहां दिया गया है:

7.17 <क्वेरी एक्सप्रेशन>


फ़ंक्शन
तालिका निर्दिष्ट करें।


प्रारूप
<क्वेरी एक्सप्रेशन> ::=
[ <क्लॉज के साथ> ] <क्वेरी एक्सप्रेशन बॉडी>
[ <क्लॉज द्वारा ऑर्डर करें> ] [ <रिजल्ट ऑफसेट क्लॉज> ] [ <पहला क्लॉज प्राप्त करें> ]
<क्लॉज के साथ> ::=[रिकर्सिव के साथ] <लिस्ट के साथ>
<लिस्ट के साथ> ::=<लिस्ट एलिमेंट के साथ> [{<कॉमा> <लिस्ट एलिमेंट के साथ>}… ]
<सूची तत्व के साथ> ::=
<क्वेरी नाम> [ <बाएं माता-पिता> <स्तंभ सूची के साथ> <दाएं माता-पिता> ]
AS <तालिका उपश्रेणी> [ <खोज या चक्र खंड> ]
<कॉलम सूची के साथ> ::=<कॉलम नाम सूची>
<क्वेरी एक्सप्रेशन बॉडी> ::=
<क्वेरी टर्म>
| <क्वेरी एक्सप्रेशन बॉडी> यूनियन [ ALL | DISTINCT ]
[ <संबंधित कल्पना> ] <क्वेरी टर्म>
| <क्वेरी एक्सप्रेशन बॉडी> सिवाय [सभी | DISTINCT ]
[ <संबंधित कल्पना> ] <क्वेरी टर्म>
<क्वेरी टर्म> ::=
<क्वेरी प्राइमरी>
| <क्वेरी टर्म> इंटरसेक्ट [ ALL | DISTINCT ]
[ <संबंधित कल्पना> ] <क्वेरी प्राथमिक>
<क्वेरी प्राथमिक> ::=
<सरल तालिका>
| <लेफ्ट पैरेन> <क्वेरी एक्सप्रेशन बॉडी>
[ <ऑर्डर बाय क्लॉज> ] [ <रिजल्ट ऑफ़सेट क्लॉज़> ] [<फ़ैच फर्स्ट क्लॉज़> ]
<राइट पैरेन>
<सिंपल टेबल> ::=
<क्वेरी विनिर्देश> | <टेबल वैल्यू कंस्ट्रक्टर> | <स्पष्ट तालिका>
<स्पष्ट तालिका> ::=तालिका <तालिका या क्वेरी नाम>
<संबंधित युक्ति> ::=
अनुरूप [ द्वारा <बाएं माता-पिता> <संबंधित स्तंभ सूची> <दायां पैरेन> ]
<संबंधित कॉलम सूची> ::=<कॉलम नाम सूची>
<खंड द्वारा आदेश> ::=<क्रमबद्ध विनिर्देश सूची द्वारा आदेश>
<परिणाम ऑफसेट खंड>::=ऑफ़सेट <ऑफ़सेट पंक्ति गणना> { पंक्ति | पंक्तियाँ }
<पहला खंड प्राप्त करें> ::=
प्राप्त करें { प्रथम | अगला} [<पहली मात्रा प्राप्त करें>] {पंक्ति | पंक्तियाँ } { केवल | टाई के साथ }
<पहली मात्रा प्राप्त करें> ::=
<पहली पंक्ति गणना प्राप्त करें>
| <पहला प्रतिशत प्राप्त करें>
<ऑफसेट पंक्ति गणना> ::=<सरल मूल्य विनिर्देश>
<पहली पंक्ति गणना प्राप्त करें> ::=<सरल मूल्य विनिर्देश>
<पहला प्रतिशत प्राप्त करें>::=<सरल मूल्य विनिर्देश> PERCENT


7.18 <खोज या चक्र खंड>


फ़ंक्शन
रिकर्सिव क्वेरी एक्सप्रेशन के परिणाम में ऑर्डरिंग और साइकिल डिटेक्शन जानकारी की पीढ़ी निर्दिष्ट करें।


प्रारूप
<खोज या चक्र खंड> ::=
<खोज खंड> | <चक्र खंड> | <खोज खंड> <चक्र खंड>
<खोज खंड> ::=
खोज <पुनरावर्ती खोज आदेश> सेट <अनुक्रम कॉलम>
<पुनरावर्ती खोज आदेश> ::=
<कॉलम नाम सूची> द्वारा सबसे पहले गहराई | चौड़ाई पहले <कॉलम नाम सूची>
<अनुक्रम कॉलम> ::=<कॉलम नाम>
<चक्र खंड> ::=
चक्र <चक्र स्तंभ सूची> सेट <चक्र चिह्न स्तंभ> के लिए <चक्र चिह्न मान>
डिफ़ॉल्ट <गैर-चक्र चिह्न मान> <पथ स्तंभ>
<चक्र स्तंभ सूची> ::=<चक्र स्तंभ> [ { <अल्पविराम> <चक्र स्तंभ> }… का उपयोग करना ]
<चक्र स्तंभ> ::=<स्तंभ नाम>
<चक्र चिह्न स्तंभ> ::=<स्तंभ नाम>
<पथ स्तंभ> ::=<स्तंभ नाम>
<साइकिल मार्क वैल्यू> ::=<वैल्यू एक्सप्रेशन>
<नॉन-साइकिल मार्क वैल्यू> ::=<वैल्यू एक्सप्रेशन>


7.3 <टेबल वैल्यू कंस्ट्रक्टर>


समारोह
<पंक्ति मान अभिव्यक्ति> का एक सेट निर्दिष्ट करें जिसे तालिका में बनाया जाना है।


प्रारूप
<तालिका मान निर्माता> ::=मान <पंक्ति मान अभिव्यक्ति सूची>
<पंक्ति मान अभिव्यक्ति सूची> ::=
<तालिका पंक्ति मान अभिव्यक्ति> [ { <अल्पविराम> <तालिका पंक्ति value अभिव्यक्ति> }… ]
<प्रासंगिक रूप से टाइप की गई तालिका मान निर्माता> ::=
VALUES <प्रासंगिक रूप से टाइप की गई पंक्ति मान अभिव्यक्ति सूची>
<प्रासंगिक रूप से टाइप की गई पंक्ति मान अभिव्यक्ति सूची> ::=
<प्रासंगिक रूप से टाइप की गई पंक्ति मान अभिव्यक्ति>
[ { <अल्पविराम> <प्रासंगिक रूप से टाइप की गई पंक्ति मान अभिव्यक्ति> }… ]

मानक शब्द क्वेरी एक्सप्रेशन एक अभिव्यक्ति का प्रतिनिधित्व करता है जिसमें एक खंड के साथ, एक सूची के साथ . शामिल है , जो एक या अधिक सूची तत्वों के साथ . से बना है , और एक बाहरी क्वेरी। T-SQL मानक सूची तत्व के साथ को संदर्भित करता है सीटीई के रूप में।

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

सीटीई के खिलाफ सरलीकृत क्वेरी के लिए टी-एसक्यूएल सिंटैक्स यहां दिया गया है:

के साथ <तालिका नाम> [(<लक्ष्य स्तंभ>)] AS(<तालिका अभिव्यक्ति>)चुनें <सूची का चयन करें><तालिका नाम से>;

संयुक्त राज्य अमेरिका के ग्राहकों का प्रतिनिधित्व करने वाले सीटीई के खिलाफ एक सरल क्वेरी के लिए यहां एक उदाहरण दिया गया है:

UC AS के साथ (बिक्री से कंपनी का नाम चुनें। ग्राहक जहां देश =N'USA') ग्राहक चुनें, कंपनी का नाम UC से;

आपको सीटीई के खिलाफ एक बयान में वही तीन भाग मिलेंगे जैसे आप एक व्युत्पन्न तालिका के खिलाफ एक बयान के साथ पाएंगे:

  1. टेबल एक्सप्रेशन (आंतरिक क्वेरी)
  2. टेबल एक्सप्रेशन को दिया गया नाम (रेंज वेरिएबल नाम)
  3. बाहरी क्वेरी

व्युत्पन्न तालिकाओं की तुलना में सीटीई के डिजाइन के बारे में अलग बात यह है कि कोड में ये तीन तत्व कहां स्थित हैं। व्युत्पन्न तालिकाओं के साथ, आंतरिक क्वेरी को बाहरी क्वेरी के FROM क्लॉज के भीतर नेस्ट किया जाता है, और टेबल एक्सप्रेशन का नाम टेबल एक्सप्रेशन के बाद ही असाइन किया जाता है। तत्व आपस में जुड़े हुए हैं। इसके विपरीत, सीटीई के साथ, कोड तीन तत्वों को अलग करता है:पहले आप टेबल एक्सप्रेशन नाम असाइन करते हैं; दूसरा आप टेबल एक्सप्रेशन निर्दिष्ट करते हैं—शुरू से अंत तक बिना किसी रुकावट के; तीसरा, आप बाहरी क्वेरी निर्दिष्ट करते हैं—शुरू से अंत तक बिना किसी रुकावट के। बाद में, "डिज़ाइन के विचार" के अंतर्गत, मैं इन डिज़ाइन अंतरों के निहितार्थों के बारे में बताऊँगा।

सीटीई के बारे में एक शब्द और एक बयान टर्मिनेटर के रूप में अर्धविराम का उपयोग। दुर्भाग्य से, मानक SQL के विपरीत, T-SQL आपको अर्धविराम के साथ सभी कथनों को समाप्त करने के लिए बाध्य नहीं करता है। हालांकि, टी-एसक्यूएल में बहुत कम मामले हैं जहां टर्मिनेटर के बिना कोड अस्पष्ट है। उन मामलों में, समाप्ति अनिवार्य है। ऐसा ही एक मामला इस तथ्य से संबंधित है कि WITH क्लॉज का उपयोग कई उद्देश्यों के लिए किया जाता है। एक सीटीई को परिभाषित करना है, दूसरा एक क्वेरी के लिए एक टेबल संकेत को परिभाषित करना है, और कुछ अतिरिक्त उपयोग के मामले हैं। एक उदाहरण के रूप में, निम्नलिखित कथन में WITH क्लॉज का उपयोग तालिका संकेत के साथ क्रमिक अलगाव स्तर को बाध्य करने के लिए किया जाता है:

बिक्री से ग्राहक चुनें, देश। (SERIALIZABLE) वाले ग्राहक;

अस्पष्टता की संभावना तब होती है जब आपके पास सीटीई परिभाषा से पहले एक अनटर्मिनेटेड स्टेटमेंट होता है, जिस स्थिति में पार्सर यह बताने में सक्षम नहीं हो सकता है कि क्लॉज पहले या दूसरे स्टेटमेंट से संबंधित है या नहीं। इसे प्रदर्शित करने वाला एक उदाहरण यहां दिया गया है:

 सेलेक्ट कस्टिड, सेल्स से देश। यूसी के रूप में ग्राहक 

यहां पार्सर यह नहीं बता सकता है कि पहले कथन में ग्राहक तालिका के लिए तालिका संकेत को परिभाषित करने के लिए WITH क्लॉज का उपयोग किया जाना चाहिए या सीटीई परिभाषा शुरू करना चाहिए। आपको निम्न त्रुटि मिलती है:

Msg 336, Level 15, State 1, Line 159
'UC' के पास गलत सिंटैक्स। यदि यह एक सामान्य तालिका अभिव्यक्ति होने का इरादा है, तो आपको पिछले कथन को अर्ध-बृहदान्त्र के साथ स्पष्ट रूप से समाप्त करने की आवश्यकता है।

फिक्स निश्चित रूप से सीटीई परिभाषा से पहले के बयान को समाप्त करने के लिए है, लेकिन एक सर्वोत्तम अभ्यास के रूप में, आपको वास्तव में अपने सभी बयानों को समाप्त करना चाहिए:

ग्राहक चुनें, बिक्री से देश।ग्राहक; यूसी एएस के साथ (सेल्स से ग्राहक का चयन करें, कंपनी का नाम। ग्राहक जहां देश =एन'यूएसए') चयन करें, कंपनी का नाम यूसी से;

आपने देखा होगा कि कुछ लोग अभ्यास के रूप में अपनी सीटीई परिभाषाओं को अर्धविराम से शुरू करते हैं, जैसे:

;UC AS के साथ (बिक्री से कंपनी का नाम चुनें। ग्राहक जहां देश =N'USA') चयन करें कस्टिड, कंपनी का नाम UC से;

इस अभ्यास में बिंदु भविष्य की त्रुटियों की संभावना को कम करना है। क्या होगा यदि बाद में कोई व्यक्ति स्क्रिप्ट में आपकी सीटीई परिभाषा के ठीक पहले एक अनटर्मिनेटेड स्टेटमेंट जोड़ता है, और पूरी स्क्रिप्ट की जाँच करने की जहमत नहीं उठाता, बल्कि केवल उनका स्टेटमेंट? WITH क्लॉज से ठीक पहले आपका अर्धविराम प्रभावी रूप से उनका स्टेटमेंट टर्मिनेटर बन जाता है। आप निश्चित रूप से इस अभ्यास की व्यावहारिकता देख सकते हैं, लेकिन यह थोड़ा अप्राकृतिक है। क्या अनुशंसा की जाती है, हालांकि इसे हासिल करना कठिन है, संगठन में अच्छी प्रोग्रामिंग प्रथाओं को स्थापित करना है, जिसमें सभी बयानों को समाप्त करना शामिल है।

सीटीई परिभाषा में आंतरिक क्वेरी के रूप में उपयोग की जाने वाली तालिका अभिव्यक्ति पर लागू होने वाले वाक्यविन्यास नियमों के संदर्भ में, वे वही हैं जो व्युत्पन्न तालिका परिभाषा में आंतरिक क्वेरी के रूप में उपयोग की जाने वाली तालिका अभिव्यक्ति पर लागू होते हैं। वे हैं:

  • टेबल एक्सप्रेशन के सभी कॉलम के नाम होने चाहिए
  • टेबल एक्सप्रेशन के सभी कॉलम नाम अद्वितीय होने चाहिए
  • टेबल एक्सप्रेशन की पंक्तियों का कोई क्रम नहीं है

विवरण के लिए, श्रृंखला के भाग 2 में "एक तालिका अभिव्यक्ति एक तालिका है" अनुभाग देखें।

डिजाइन संबंधी विचार

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

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

CTE में पुनरावर्ती क्वेरी क्षमताएं होती हैं और व्युत्पन्न तालिकाएं नहीं होती हैं। इसलिए, यदि आपको उन पर भरोसा करने की आवश्यकता है, तो आप स्वाभाविक रूप से सीटीई के साथ जाएंगे। पुनरावर्ती प्रश्न अगले महीने के लेख का फोकस हैं।

भाग 2 में मैंने समझाया कि मैं व्युत्पन्न तालिकाओं के घोंसले को कोड में जटिलता जोड़ने के रूप में देखता हूं, क्योंकि इससे तर्क का पालन करना कठिन हो जाता है। मैंने निम्नलिखित उदाहरण प्रदान किए, उन ऑर्डर वर्षों की पहचान करना जिनमें 70 से अधिक ग्राहकों ने ऑर्डर दिए:

सेलेक्ट ऑर्डरवर्ष, numcustsFROM (सेलेक्ट ऑर्डरईयर, COUNT(DISTINCT custid) से numcusts के रूप में (सेलेक्ट ईयर (ऑर्डर की तारीख) ऑर्डर ईयर के रूप में, सेल्स से कस्टिड। ऑर्डर) एएस डी 1 ग्रुप बाय ऑर्डर ईयर) डी 2 के रूप में जहां numcusts> 70;

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

सीटीई का उपयोग करके उपरोक्त कार्य का समाधान यहां दिया गया है:

सी1 एएस के साथ (सेलेक्ट ईयर (ऑर्डरडेट) ऑर्डर ईयर के रूप में, सेल्स से कस्टिड। ऑर्डर), सी 2 एएस (सेलेक्ट ऑर्डर ईयर, काउंट (डिस्टिंक्ट कस्टिड) के रूप में सी 1 ग्रुप से ऑर्डर ईयर) सेलेक्ट ऑर्डर ईयर, numcustsF2C2WHERE numcusts> 70; 

मुझे सीटीई-आधारित समाधान बेहतर लगता है। लेकिन फिर से, अनुभवी डेवलपर्स से पूछें कि वे उपरोक्त दो समाधानों में से कौन सा पसंद करते हैं, और वे सभी सहमत नहीं होंगे। कुछ वास्तव में नेस्टेड लॉजिक को पसंद करते हैं, और सब कुछ एक ही स्थान पर देखने में सक्षम होते हैं।

व्युत्पन्न तालिकाओं पर सीटीई का एक बहुत स्पष्ट लाभ यह है कि जब आपको अपने समाधान में एक ही तालिका अभिव्यक्ति के कई उदाहरणों के साथ बातचीत करने की आवश्यकता होती है। श्रृंखला के भाग 2 से व्युत्पन्न तालिकाओं के आधार पर निम्नलिखित उदाहरण याद रखें:

CUR.orderyear, CUR.numorders, CUR.numorders चुनें - PRV.numorders as diffFROM (चुनें वर्ष (आदेश दिनांक) ऑर्डर वर्ष के रूप में, COUNT (*) बिक्री से संख्या के रूप में। वर्ष द्वारा आदेश समूह (आदेश दिनांक)) CUR LEFT के रूप में आउटर जॉइन (चुनें वर्ष (आदेश दिनांक) ऑर्डर वर्ष के रूप में, COUNT (*) बिक्री से संख्याओं के रूप में। वर्ष द्वारा ऑर्डर समूह (आदेश दिनांक)) CUR पर पीआरवी के रूप में। आदेश वर्ष =पीआरवी.आदेश वर्ष + 1;

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

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

ऑर्डकाउंट एएस के साथ (सेलेक्ट ईयर (ऑर्डरडेट) ऑर्डर ईयर के रूप में, काउंट (*) सेल्स से नंबर के रूप में। ऑर्डर ग्रुप बाय ईयर (ऑर्डरडेट)) सेलेक्ट सीयूआर.ऑर्डर ईयर, सीयूआर.नंबर्स, सीयूआर.नंबर्स - पीआरवी। CUR LEFT OUTER के रूप में OrdCount CUR.orderyear =PRV.orderyear + 1;
पर पीआरवी के रूप में ऑर्डकाउंट में शामिल हों

इस समाधान में व्युत्पन्न तालिकाओं के आधार पर एक स्पष्ट प्रोग्राम योग्यता लाभ है जिसमें आपको एक ही तालिका अभिव्यक्ति की दो प्रतियों को बनाए रखने की आवश्यकता नहीं है। भौतिक प्रसंस्करण के दृष्टिकोण से इसके बारे में कहने के लिए और भी बहुत कुछ है, और इसकी तुलना अस्थायी तालिकाओं के उपयोग से करें, लेकिन मैं ऐसा भविष्य के एक लेख में करूँगा जो प्रदर्शन पर केंद्रित है।

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

सी एएस के साथ (आदेश वर्ष चुनें, क्रमांक चुनें (आदेश वर्ष चुनें, COUNT(DISTINCT कस्टिड) से अंकगणित के रूप में (चयन वर्ष (आदेश दिनांक) आदेश वर्ष के रूप में, बिक्री से संरक्षक। आदेश) एएस डी1 समूह द्वारा आदेश वर्ष) के रूप में डी2 जहां अंक> 70)आदेश वर्ष चुनें, सी से अंक;

हालांकि, सीटीई पर आधारित एक प्रश्न के लिए यह सही नहीं है। भले ही इसे अवधारणात्मक रूप से एक तालिका अभिव्यक्ति माना जाता है, आप इसे व्युत्पन्न तालिका परिभाषाओं, उपश्रेणियों और स्वयं CTE में आंतरिक क्वेरी के रूप में उपयोग नहीं कर सकते। उदाहरण के लिए, निम्न कोड T-SQL में मान्य नहीं है:

सेलेक्ट ऑर्डर ईयर, कस्टिडफ्रॉम (सी1 एएस के साथ (सेलेक्ट ईयर (ऑर्डरडेट) ऑर्डर ईयर के रूप में, सेल्स से कस्टिड। ऑर्डर), सी 2 एएस (सेलेक्ट ऑर्डर ईयर, काउंट (डिस्टिंक्ट कस्टिड) ऑर्डर ईयर के हिसाब से सी 1 ग्रुप से अंक के रूप में) ऑर्डर ईयर, numcusts चुनें C2 से जहां numcusts> 70) AS D;

अच्छी खबर यह है कि आप एक ऐसी क्वेरी का उपयोग कर सकते हैं जो सीटीई पर आधारित विचारों और इनलाइन तालिका-मूल्यवान कार्यों में आंतरिक क्वेरी के रूप में है, जिसे मैं भविष्य के लेखों में शामिल करता हूं।

साथ ही, याद रखें, आप हमेशा अंतिम क्वेरी के आधार पर एक और सीटीई परिभाषित कर सकते हैं, और फिर उस सीटीई के साथ सबसे बाहरी क्वेरी इंटरैक्ट कर सकते हैं:

सी1 एएस के साथ (सेलेक्ट ईयर (ऑर्डरडेट) ऑर्डर ईयर के रूप में, सेल्स से कस्टिड। ऑर्डर), सी 2 एएस (सेलेक्ट ऑर्डर ईयर, काउंट (डिस्टिंक्ट कस्टिड) एएस न्यूमस्ट्स फ्रॉम सी 1 ग्रुप बाय ऑर्डर ईयर), सी 3 एएस (सेलेक्ट ऑर्डर ईयर, सेलेक्ट्स फ्रॉम C2 जहां numcusts > 70)ऑर्डर वर्ष चुनें, C3 से numcusts;

समस्या निवारण के दृष्टिकोण से, जैसा कि उल्लेख किया गया है, मुझे आमतौर पर व्युत्पन्न तालिकाओं पर आधारित कोड की तुलना में सीटीई पर आधारित कोड के तर्क का पालन करना आसान लगता है। हालांकि, व्युत्पन्न तालिकाओं पर आधारित समाधानों का एक फायदा यह है कि आप किसी भी नेस्टिंग स्तर को हाइलाइट कर सकते हैं और इसे स्वतंत्र रूप से चला सकते हैं, जैसा कि चित्र 1 में दिखाया गया है।

चित्र 1:व्युत्पन्न तालिकाओं के साथ कोड के भाग को हाइलाइट और चला सकते हैं

सीटीई के साथ चीजें मुश्किल होती हैं। सीटीई को शामिल करने वाले कोड को चलाने योग्य होने के लिए, इसे खंड के साथ शुरू करना होगा, इसके बाद अल्पविराम द्वारा अलग किए गए एक या अधिक नामित कोष्ठक तालिका अभिव्यक्तियां होनी चाहिए, इसके बाद बिना किसी पूर्ववर्ती अल्पविराम के एक गैर-संक्षिप्त क्वेरी होनी चाहिए। आप किसी भी आंतरिक प्रश्न को हाइलाइट करने और चलाने में सक्षम हैं जो वास्तव में आत्मनिर्भर हैं, साथ ही साथ संपूर्ण समाधान का कोड भी; हालांकि, आप समाधान के किसी अन्य मध्यवर्ती भाग को हाइलाइट और सफलतापूर्वक नहीं चला सकते हैं। उदाहरण के लिए, चित्र 2 में C2 का प्रतिनिधित्व करने वाले कोड को चलाने का असफल प्रयास दिखाया गया है।

चित्र 2:सीटीई के साथ कोड के भाग को हाइलाइट और चला नहीं सकता

तो सीटीई के साथ, समाधान के मध्यवर्ती चरण का निवारण करने में सक्षम होने के लिए आपको कुछ अजीब तरीकों का सहारा लेना होगा। उदाहरण के लिए, एक सामान्य समाधान अस्थायी रूप से प्रासंगिक CTE के ठीक नीचे your_cte क्वेरी से SELECT * FROM को इंजेक्ट करना है। फिर आप इंजेक्शन वाली क्वेरी सहित कोड को हाइलाइट करते हैं और चलाते हैं, और जब आप पूरा कर लेते हैं, तो आप इंजेक्ट की गई क्वेरी को हटा देते हैं। चित्र 3 इस तकनीक को प्रदर्शित करता है।

चित्र 3:प्रासंगिक सीटीई के नीचे चयन * इंजेक्ट करें

समस्या यह है कि जब भी आप कोड में बदलाव करते हैं—यहां तक ​​कि ऊपर दिए गए अस्थायी नाबालिग भी—एक मौका है कि जब आप मूल कोड पर वापस लौटने का प्रयास करते हैं, तो आप एक नया बग पेश करेंगे।

एक अन्य विकल्प यह है कि आप अपने कोड को थोड़ा अलग तरीके से स्टाइल करें, जैसे कि प्रत्येक गैर-प्रथम CTE परिभाषा कोड की एक अलग पंक्ति से शुरू होती है जो इस तरह दिखती है:

, cte_name AS (

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

चित्र 4:कोड की एक पंक्ति पर टिप्पणी को सक्षम करने के लिए सिंटैक्स को पुनर्व्यवस्थित करें

यदि आप इस शैली से खुश नहीं हैं, तो आपके पास एक और विकल्प है। आप एक ब्लॉक टिप्पणी का उपयोग कर सकते हैं जो अल्पविराम से ठीक पहले शुरू होती है जो ब्याज के सीटीई से पहले होती है और खुले कोष्ठक के बाद समाप्त होती है, जैसा कि चित्र 5 में दिखाया गया है।

चित्र 5:ब्लॉक टिप्पणी का उपयोग करें

यह व्यक्तिगत प्राथमिकताओं के लिए उबलता है। मैं आमतौर पर अस्थायी रूप से इंजेक्ट की गई SELECT * क्वेरी तकनीक का उपयोग करता हूं।

टेबल वैल्यू कंस्ट्रक्टर

मानक की तुलना में टेबल वैल्यू कंस्ट्रक्टर्स के लिए टी-एसक्यूएल के समर्थन में एक निश्चित सीमा है। यदि आप निर्माण से परिचित नहीं हैं, तो पहले श्रृंखला में भाग 2 की जाँच करना सुनिश्चित करें, जहाँ मैं इसका विस्तार से वर्णन करता हूँ। जबकि टी-एसक्यूएल आपको टेबल वैल्यू कंस्ट्रक्टर के आधार पर व्युत्पन्न तालिका को परिभाषित करने की अनुमति देता है, यह आपको टेबल वैल्यू कंस्ट्रक्टर के आधार पर सीटीई को परिभाषित करने की अनुमति नहीं देता है।

यहां एक समर्थित उदाहरण दिया गया है जो व्युत्पन्न तालिका का उपयोग करता है:

कस्टिड, कंपनी का नाम, अनुबंध दिनांक चुनें ( VALUES( 2, 'Cust 2', '20200212' ), ( 3, 'Cust 3', '20200118' ), (5, 'Cust 5', '20200401' )) MyCusts के रूप में (कस्टिड, कंपनी का नाम, अनुबंध की तारीख);

दुर्भाग्य से, सीटीई का उपयोग करने वाला समान कोड समर्थित नहीं है:

साथ MyCusts(custid, companyname, कॉन्ट्रैक्टडेट) AS( VALUES( 2, 'Cust 2', '20200212' ),( 3, 'Cust 3', '20200118' ),( 5, 'Cust 5', ' 20200401' )) MyCusts से कस्टिड, कंपनी का नाम, अनुबंध की तारीख चुनें;

यह कोड निम्न त्रुटि उत्पन्न करता है:

Msg 156, Level 15, State 1, Line 337
कीवर्ड 'VALUES' के पास गलत सिंटैक्स।

हालांकि, कुछ कामकाज हैं। एक व्युत्पन्न तालिका के खिलाफ एक क्वेरी का उपयोग करना है, जो बदले में एक टेबल वैल्यू कंस्ट्रक्टर पर आधारित है, जैसे कि CTE की आंतरिक क्वेरी, जैसे:

MyCusts AS के साथ (चुनें * से ( VALUES( 2, 'Cust 2', '20200212'), ( 3, 'Cust 3', '20200118' ), (5, 'Cust 5', '20200401' ) ) MyCusts के रूप में (कस्टिड, कंपनी का नाम, अनुबंध की तारीख)) MyCusts से कस्टिड, कंपनी का नाम, अनुबंध की तारीख चुनें;

एक और तकनीक का सहारा लेना है जिसका उपयोग टेबल-वैल्यू कंस्ट्रक्टर्स को टी-एसक्यूएल में पेश करने से पहले लोगों ने किया था - UNION ALL ऑपरेटरों द्वारा अलग किए गए FROMless प्रश्नों की एक श्रृंखला का उपयोग करना, जैसे:

MyCusts(custid, companyname, Contractdate) AS(सेलेक्ट 2, 'Cust 2', '20200212' UNION ALL SELECT 3, 'Cust 3', '20200118' UNION ALL SELECT 5, 'Cust 5', '20200401 के साथ ') MyCusts से संरक्षक, कंपनी का नाम, अनुबंध तिथि चुनें;

ध्यान दें कि कॉलम उपनाम सीटीई नाम के ठीक बाद दिए गए हैं।

दो विधियों को बीजगणित और अनुकूलित किया जाता है, इसलिए जो भी आप अधिक सहज महसूस करते हैं उसका उपयोग करें।

संख्याओं का एक क्रम तैयार करना

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

DECLARE @low AS BIGINT =1001, @high AS BIGINT =1010; एल0 एएस के साथ (सेलेक्ट 1 एएस सी (वैल्यू (1), (1)) एएस डी (सी)), एल 1 एएस (एल0 से सी 1 एएस को क्रॉस जॉइन एल0 एएस बी के रूप में चुनें), एल 2 एएस (चुनें 1 एएस) सी एल 1 से एक क्रॉस जॉइन एल 1 एएस बी के रूप में), एल 3 एएस (एल 2 से सी को क्रॉस जॉइन एल 2 एएस बी के रूप में चुनें), एल 4 एएस (एल 3 से एक क्रॉस जॉइन एल 3 एएस बी के रूप में चुनें), एल 5 एएस (एक क्रॉस जॉइन एल4 एएस बी के रूप में एल4 से 1 के रूप में चयन करें), संख्या के रूप में (चयन ROW_NUMBER() ओवर (ऑर्डर बाय (चुनें न्यूल)) एल 5 से राउनम के रूप में) शीर्ष चुनें (@high - @low + 1) @low + राउनम - 1 के रूप में nFROM nFROM nFROM Rownum द्वारा;

यह कोड निम्न आउटपुट उत्पन्न करता है:

n-----1001100210031004100510061007100810091010

L0 नामक पहला CTE दो पंक्तियों के साथ एक टेबल वैल्यू कंस्ट्रक्टर पर आधारित है। वहां के वास्तविक मूल्य महत्वहीन हैं; महत्वपूर्ण बात यह है कि इसमें दो पंक्तियाँ हैं। फिर, एल1 से एल5 नामक पांच अतिरिक्त सीटीई का एक क्रम है, प्रत्येक पूर्ववर्ती सीटीई के दो उदाहरणों के बीच एक क्रॉस जॉइन लागू करता है। निम्नलिखित कोड प्रत्येक सीटीई द्वारा संभावित रूप से उत्पन्न पंक्तियों की संख्या की गणना करता है, जहां @L सीटीई स्तर की संख्या है:

DECLARE @L AS INT =5; पावर चुनें(2., पावर(2., @एल));

यहां हर सीटीई के लिए आपको मिलने वाले नंबर दिए गए हैं:

CTE कार्डिनैलिटी
L0 2
L1 4
L2 16
L3 256
L4 65,536
L5 4,294,967,296

स्तर 5 तक जाने से आपको चार अरब से अधिक पंक्तियाँ मिलती हैं। यह किसी भी व्यावहारिक उपयोग के मामले के लिए पर्याप्त होना चाहिए जिसके बारे में मैं सोच सकता हूं। अगला कदम CTE में होता है जिसे Nums कहा जाता है। आप एक ROW_NUMBER फ़ंक्शन का उपयोग बिना किसी परिभाषित क्रम (ORDER BY (SELECT NULL)) के आधार पर 1 से शुरू होने वाले पूर्णांकों के अनुक्रम को उत्पन्न करने के लिए करते हैं, और परिणाम कॉलम राउनम का नाम देते हैं। अंत में, बाहरी क्वेरी वांछित अनुक्रम कार्डिनैलिटी (@high - @low + 1) के रूप में कई संख्याओं को फ़िल्टर करने के लिए राउनम ऑर्डरिंग के आधार पर एक TOP फ़िल्टर का उपयोग करती है, और परिणाम संख्या n को @low + rownum - 1. के रूप में परिकलित करती है।>

यहां आप वास्तव में सीटीई डिजाइन में सुंदरता और उस बचत की सराहना कर सकते हैं जो मॉड्यूलर फैशन में समाधान बनाते समय इसे सक्षम बनाता है। अंततः, अननेस्टिंग प्रक्रिया 32 तालिकाओं को खोलती है, जिनमें से प्रत्येक में स्थिरांक के आधार पर दो पंक्तियाँ होती हैं। यह इस कोड के निष्पादन योजना में स्पष्ट रूप से देखा जा सकता है, जैसा कि सेंट्रीऑन प्लान एक्सप्लोरर का उपयोग करके चित्र 6 में दिखाया गया है।

चित्र 6:संख्याओं के क्वेरी जनरेटिंग अनुक्रम के लिए योजना

प्रत्येक लगातार स्कैन ऑपरेटर दो पंक्तियों के साथ स्थिरांक की एक तालिका का प्रतिनिधित्व करता है। बात यह है कि, शीर्ष ऑपरेटर वह है जो उन पंक्तियों का अनुरोध करता है, और यह वांछित संख्या प्राप्त करने के बाद शॉर्ट सर्किट करता है। शीर्ष ऑपरेटर में बहने वाले तीर के ऊपर इंगित 10 पंक्तियों पर ध्यान दें।

मुझे पता है कि इस लेख का फोकस सीटीई के वैचारिक उपचार पर है, न कि भौतिक/प्रदर्शन संबंधी विचारों पर, लेकिन योजना को देखकर आप वास्तव में कोड की संक्षिप्तता की सराहना कर सकते हैं, जो कि पर्दे के पीछे के अनुवाद की लंबी-घुमावदारता की तुलना में है।

व्युत्पन्न तालिकाओं का उपयोग करके, आप वास्तव में एक समाधान लिख सकते हैं जो प्रत्येक सीटीई संदर्भ को अंतर्निहित क्वेरी के साथ प्रतिस्थापित करता है जिसका वह प्रतिनिधित्व करता है। आपको जो मिलता है वह काफी डरावना होता है:

DECLARE @low AS BIGINT =1001, @high AS BIGINT =1010; शीर्ष चुनें (@high - @low + 1) @low + rownum - 1 AS nFROM (सेलेक्ट ROW_NUMBER() ओवर (ऑर्डर बाय (सिलेक्ट न्यूल)) से राउनम के रूप में (सेलेक्ट 1 एएस सी से (चुनें 1 एएस सी से चुनें (चुनें) 1 के रूप में सी से (चुनें 1 के रूप में सी (मान (1), (1)) के रूप में डी 01 (सी) क्रॉस जॉइन (मान (1), (1)) डी 02 (सी) के रूप में डी 3 क्रॉस जॉइन के रूप में (चुनें 1 एएस सी से (मान (1), (1)) डी 01 (सी) क्रॉस जॉइन (मान (1), (1)) डी 02 (सी) के रूप में) डी 4 के रूप में) डी 5 क्रॉस जॉइन के रूप में ( से 1 के रूप में सी चुनें ( से 1 के रूप में सी चुनें (मान (1), (1)) के रूप में डी 01 (सी) क्रॉस जॉइन (VALUES(1),(1)) AS D02(c) ) AS D3 क्रॉस जॉइन (चुनें 1 AS C से (Values(1),(1)) AS D01(c) क्रॉस जॉइन (Value(1),( 1)) AS D02(c)) AS D4) AS D6) AS D7 क्रॉस जॉइन (सेलेक्ट 1 AS C से (चुनें 1 AS C से (चुनें 1 AS C से (VALUES(1),(1)) AS D01( सी) क्रॉस जॉइन (मान (1), (1)) डी 02 (सी) के रूप में) डी 3 क्रॉस जॉइन के रूप में (सी से 1 के रूप में चुनें (मान (1), (1)) डी 01 (सी) क्रॉस जॉइन (मान (मान) 1),(1)) AS D02(c) ) AS D4 ) AS D5 क्रॉस जॉइन (से 1 के रूप में सी चुनें (से 1 के रूप में सी चुनें (मूल्य (1), (1)) डी 01 के रूप में (सी) क्रॉस जॉइन (मान (1), (1)) डी 02 (सी) के रूप में डी 3 क्रॉस जॉइन के रूप में ( (मान (1), (1)) के रूप में डी01 (सी) क्रॉस जॉइन (मूल्य (1), (1)) डी 02 (सी) के रूप में डी 4) के रूप में डी 6) के रूप में डी 8 के रूप में) डी 9 क्रॉस के रूप में 1 के रूप में चुनें JOIN ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1 )) AS D02(c) ) AS D3 CROSS JOIN ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D4 ) AS D5 CROSS JOIN ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D3 CROSS JOIN ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D4 ) AS D6 ) AS D7 CROSS JOIN ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM (VALUES(1),(1) ) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D3 CROSS JOIN ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D4 ) AS D5 CROSS JOIN ( SELECT 1 AS C FROM ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D3 CROSS JOIN ( SELECT 1 AS C FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) ) AS D4 ) AS D6 ) AS D8 ) AS D10 ) AS NumsORDER BY rownum;

Obviously, you don’t want to write a solution like this, but it’s a good way to illustrate what SQL Server does behind the scenes with your CTE code.

If you were really planning to write a solution based on derived tables, instead of using the above nested approach, you’d be better off simplifying the logic to a single query with 31 cross joins between 32 table value constructors, each based on two rows, like so:

DECLARE @low AS BIGINT =1001, @high AS BIGINT =1010; SELECT TOP(@high - @low + 1) @low + rownum - 1 AS nFROM ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum FROM (VALUES(1),(1)) AS D01(c) CROSS JOIN (VALUES(1),(1)) AS D02(c) CROSS JOIN (VALUES(1),(1)) AS D03(c) CROSS JOIN (VALUES(1),(1)) AS D04(c) CROSS JOIN (VALUES(1),(1)) AS D05(c) CROSS JOIN (VALUES(1),(1)) AS D06(c) CROSS JOIN (VALUES(1),(1)) AS D07(c) CROSS JOIN (VALUES(1),(1)) AS D08(c) CROSS JOIN (VALUES(1),(1)) AS D09(c) CROSS JOIN (VALUES(1),(1)) AS D10(c) CROSS JOIN (VALUES(1),(1)) AS D11(c) CROSS JOIN (VALUES(1),(1)) AS D12(c) CROSS JOIN (VALUES(1),(1)) AS D13(c) CROSS JOIN (VALUES(1),(1)) AS D14(c) CROSS JOIN (VALUES(1),(1)) AS D15(c) CROSS JOIN (VALUES(1),(1)) AS D16(c) CROSS JOIN (VALUES(1),(1)) AS D17(c) CROSS JOIN (VALUES(1),(1)) AS D18(c) CROSS JOIN (VALUES(1),(1)) AS D19(c) CROSS JOIN (VALUES(1),(1)) AS D20(c) CROSS JOIN (VALUES(1),(1)) AS D21(c) CROSS JOIN (VALUES(1),(1)) AS D22(c) CROSS JOIN (VALUES(1),(1)) AS D23(c) CROSS JOIN (VALUES(1),(1)) AS D24(c) CROSS JOIN (VALUES(1),(1)) AS D25(c) CROSS JOIN (VALUES(1),(1)) AS D26(c) CROSS JOIN (VALUES(1),(1)) AS D27(c) CROSS JOIN (VALUES(1),(1)) AS D28(c) CROSS JOIN (VALUES(1),(1)) AS D29(c) CROSS JOIN (VALUES(1),(1)) AS D30(c) CROSS JOIN (VALUES(1),(1)) AS D31(c) CROSS JOIN (VALUES(1),(1)) AS D32(c) ) AS NumsORDER BY rownum;

Still, the solution based on CTEs is obviously significantly simpler. The plans are identical.

Used in modification statements

CTEs can be used as the source and target tables in INSERT, UPDATE, DELETE and MERGE statements. They cannot be used in the TRUNCATE statement.

The syntax is pretty straightforward. You start the statement as usual with a WITH clause, followed by one or more CTEs separated by commas. Then you specify the outer modification statement, which interacts with the CTEs that were defined under the WITH clause as the source tables, target table, or both. Just like I explained in Part 2 about derived tables, also with CTEs what really gets modified is the underlying base table that the table expression uses. I’ll show a couple of examples using DELETE and UPDATE statements, but remember that you can use CTEs in MERGE and INSERT statements as well.

Here’s the general syntax of a DELETE statement against a CTE:

WITH  [ () ] AS( 
)DELETE [ FROM ]
[ WHERE ];

As an example (don’t actually run it), the following code deletes the 10 oldest orders:

WITH OldestOrders AS( SELECT TOP (10) * FROM Sales.Orders ORDER BY orderdate, orderid)DELETE FROM OldestOrders;

Here’s the general syntax of an UPDATE statement against a CTE:

WITH 
[ () ] AS(
)UPDATE
SET [ WHERE ];

As an example, the following code updates the 10 oldest unshipped orders that have an overdue required date, increasing the required date to 10 days from today:

BEGIN TRAN; WITH OldestUnshippedOrders AS( SELECT TOP (10) orderid, requireddate, DATEADD(day, 10, CAST(SYSDATETIME() AS DATE)) AS newrequireddate FROM Sales.Orders WHERE shippeddate IS NULL AND requireddate < CAST(SYSDATETIME() AS DATE) ORDER BY orderdate, orderid)UPDATE OldestUnshippedOrders SET requireddate =newrequireddate OUTPUT inserted.orderid, deleted.requireddate AS oldrequireddate, inserted.requireddate AS newrequireddate; ROLLBACK TRAN;

The code applies the update in a transaction that it then rolls back so that the change won’t stick.

This code generates the following output, showing both the old and the new required dates:

orderid oldrequireddate newrequireddate----------- --------------- ---------------11008 2019-05-06 2020-07-1611019 2019-05-11 2020-07-1611039 2019-05-19 2020-07-1611040 2019-05-20 2020-07-1611045 2019-05-21 2020-07-1611051 2019-05-25 2020-07-1611054 2019-05-26 2020-07-1611058 2019-05-27 2020-07-1611059 2019-06-10 2020-07-1611061 2019-06-11 2020-07-16(10 rows affected)

Of course you will get a different new required date based on when you run this code.

सारांश

I like CTEs. They have a few advantages compared to derived tables. Instead of nesting the code, you define multiple CTEs separated by commas, typically leading to a more modular solution that is easier to review and maintain. Also, you can have multiple references to the same CTE name in the outer statement, so you don’t need to repeat the inner table expression’s code. However, unlike derived tables, CTEs cannot be defined directly based on a table value constructor, and you cannot highlight and execute some of the intermediate parts of the code. The following table summarizes the differences between derived tables and CTEs:

Item Derived table CTE
Supports nesting Yes No
Supports multiple references No Yes
Supports table value constructor Yes No
Can highlight and run part of code Yes No
Supports recursion No Yes

As the last item says, derived tables do not support recursive capabilities, whereas CTEs do. Recursive queries are the focus of next month’s article.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. स्लाइड डेक और नमूने #SQLintersection . से

  2. कैसे जांचें कि कोई टी-एसक्यूएल यूडीएफ स्कीमा बाध्य है (यहां तक ​​​​कि जब यह एन्क्रिप्ट किया गया हो)

  3. चुनौती चालू है! सबसे तेज संख्या श्रृंखला जनरेटर बनाने के लिए सामुदायिक कॉल

  4. आधार रेखा का महत्व

  5. SQL में कोडड के नियम