ISO/IEC 9075:2016 मानक (SQL:2016) नेस्टेड विंडो फ़ंक्शन नामक एक विशेषता को परिभाषित करता है। यह सुविधा आपको विंडो एग्रीगेट फ़ंक्शन के तर्क के रूप में दो प्रकार के विंडो फ़ंक्शंस को नेस्ट करने की अनुमति देती है। विचार यह है कि आप विंडोिंग तत्वों में रणनीतिक मार्करों पर या तो एक पंक्ति संख्या, या अभिव्यक्ति के मूल्य को संदर्भित करने की अनुमति दें। मार्कर आपको विभाजन में पहली या अंतिम पंक्ति, फ़्रेम में पहली या अंतिम पंक्ति, वर्तमान बाहरी पंक्ति और वर्तमान फ़्रेम पंक्ति तक पहुँच प्रदान करते हैं। यह विचार बहुत शक्तिशाली है, जिससे आप अपने विंडो फ़ंक्शन के भीतर फ़िल्टरिंग और अन्य प्रकार के जोड़तोड़ को लागू कर सकते हैं जो कभी-कभी अन्यथा हासिल करना मुश्किल होता है। आप RANGE-आधारित फ़्रेम जैसी अन्य सुविधाओं का आसानी से अनुकरण करने के लिए नेस्टेड विंडो फ़ंक्शंस का भी उपयोग कर सकते हैं। यह सुविधा वर्तमान में टी-एसक्यूएल में उपलब्ध नहीं है। मैंने नेस्टेड विंडो फ़ंक्शंस के लिए समर्थन जोड़कर SQL सर्वर को बेहतर बनाने के लिए एक सुझाव पोस्ट किया। अगर आपको लगता है कि यह सुविधा आपके लिए फायदेमंद हो सकती है तो अपना वोट जोड़ना सुनिश्चित करें।
नेस्टेड विंडो फंक्शन किस बारे में नहीं हैं
इस लेखन की तारीख में, वास्तविक मानक नेस्टेड विंडो फ़ंक्शंस के बारे में बहुत अधिक जानकारी उपलब्ध नहीं है। जो चीज इसे कठिन बनाती है, वह यह है कि मुझे अभी तक इस सुविधा को लागू करने वाले किसी भी प्लेटफॉर्म के बारे में पता नहीं है। वास्तव में, नेस्टेड विंडो फ़ंक्शंस के लिए एक वेब खोज चलाने से विंडोड एग्रीगेट फ़ंक्शंस के भीतर नेस्टिंग ग्रुपेड एग्रीगेट फ़ंक्शंस के बारे में अधिकतर कवरेज और चर्चा मिलती है। उदाहरण के लिए, मान लें कि आप TSQLV5 नमूना डेटाबेस में Sales.OrderValues दृश्य को क्वेरी करना चाहते हैं, और प्रत्येक ग्राहक और ऑर्डर तिथि, ऑर्डर मानों का दैनिक कुल, और वर्तमान दिन तक चलने वाले कुल के लिए वापस लौटना चाहते हैं। इस तरह के कार्य में समूहीकरण और विंडोिंग दोनों शामिल हैं। आप ग्राहक आईडी और ऑर्डर तिथि के आधार पर पंक्तियों को समूहित करते हैं, और ऑर्डर मानों के समूह योग के शीर्ष पर एक रनिंग योग लागू करते हैं, जैसे:
USE TSQLV5; -- https://tsql.solidq.com/SampleDatabases/TSQLV5.zip
SELECT custid, orderdate, SUM(val) AS daytotal,
SUM(SUM(val)) OVER(PARTITION BY custid
ORDER BY orderdate
ROWS UNBOUNDED PRECEDING) AS runningsum
FROM Sales.OrderValues
GROUP BY custid, orderdate; यह क्वेरी निम्नलिखित आउटपुट उत्पन्न करती है, जिसे यहाँ संक्षिप्त रूप में दिखाया गया है:
custid orderdate daytotal runningsum ------- ---------- -------- ---------- 1 2018-08-25 814.50 814.50 1 2018-10-03 878.00 1692.50 1 2018-10-13 330.00 2022.50 1 2019-01-15 845.80 2868.30 1 2019-03-16 471.20 3339.50 1 2019-04-09 933.50 4273.00 2 2017-09-18 88.80 88.80 2 2018-08-08 479.75 568.55 2 2018-11-28 320.00 888.55 2 2019-03-04 514.40 1402.95 ...
भले ही यह तकनीक बहुत अच्छी है, और भले ही नेस्टेड विंडो फ़ंक्शंस के लिए वेब खोज मुख्य रूप से ऐसी तकनीकों को लौटाती है, लेकिन नेस्टेड विंडो फ़ंक्शंस द्वारा SQL मानक का अर्थ यह नहीं है। चूंकि मुझे इस विषय पर कोई जानकारी नहीं मिली, इसलिए मुझे इसे मानक से ही पता लगाना था। उम्मीद है, यह लेख ट्रू नेस्टेड विंडो फ़ंक्शन फ़ीचर के बारे में जागरूकता बढ़ाएगा, और लोगों को Microsoft की ओर रुख करने और SQL सर्वर में इसके लिए समर्थन जोड़ने के लिए कहेगा।
नेस्टेड विंडो फंक्शन किस बारे में हैं
नेस्टेड विंडो फ़ंक्शंस में दो फ़ंक्शन शामिल होते हैं जिन्हें आप विंडो एग्रीगेट फ़ंक्शन के तर्क के रूप में नेस्ट कर सकते हैं। वे नेस्टेड पंक्ति संख्या फ़ंक्शन हैं, और पंक्ति फ़ंक्शन पर नेस्टेड value_of अभिव्यक्ति हैं।
नेस्टेड पंक्ति संख्या फ़ंक्शन
नेस्टेड पंक्ति संख्या फ़ंक्शन आपको विंडोिंग तत्वों में रणनीतिक मार्करों की पंक्ति संख्या को संदर्भित करने की अनुमति देता है। यहाँ फ़ंक्शन का सिंटैक्स है:
आप जिन पंक्ति मार्करों को निर्दिष्ट कर सकते हैं वे हैं:
- BEGIN_PARTITION
- END_PARTITION
- BEGIN_FRAME
- END_FRAME
- CURRENT_ROW
- FRAME_ROW
पहले चार मार्कर स्व-व्याख्यात्मक हैं। पिछले दो के लिए, CURRENT_ROW मार्कर वर्तमान बाहरी पंक्ति का प्रतिनिधित्व करता है, और FRAME_ROW वर्तमान आंतरिक फ़्रेम पंक्ति का प्रतिनिधित्व करता है।
नेस्टेड पंक्ति संख्या फ़ंक्शन का उपयोग करने के लिए एक उदाहरण के रूप में, निम्न कार्य पर विचार करें। आपको Sales.OrderValues दृश्य को क्वेरी करने की आवश्यकता है, और प्रत्येक ऑर्डर के लिए उसकी कुछ विशेषताओं के साथ-साथ वर्तमान ऑर्डर मूल्य और ग्राहक औसत के बीच के अंतर को वापस करना होगा, लेकिन औसत से पहले और अंतिम ग्राहक ऑर्डर को छोड़कर।
यह कार्य नेस्टेड विंडो फ़ंक्शन के बिना प्राप्त किया जा सकता है, लेकिन समाधान में कुछ चरण शामिल हैं:
WITH C1 AS
(
SELECT custid, val,
ROW_NUMBER() OVER( PARTITION BY custid
ORDER BY orderdate, orderid ) AS rownumasc,
ROW_NUMBER() OVER( PARTITION BY custid
ORDER BY orderdate DESC, orderid DESC ) AS rownumdesc
FROM Sales.OrderValues
),
C2 AS
(
SELECT custid, AVG(val) AS avgval
FROM C1
WHERE 1 NOT IN (rownumasc, rownumdesc)
GROUP BY custid
)
SELECT O.orderid, O.custid, O.orderdate, O.val,
O.val - C2.avgval AS diff
FROM Sales.OrderValues AS O
LEFT OUTER JOIN C2
ON O.custid = C2.custid; यहाँ इस क्वेरी का आउटपुट है, जिसे यहाँ संक्षिप्त रूप में दिखाया गया है:
orderid custid orderdate val diff -------- ------- ---------- -------- ------------ 10411 10 2018-01-10 966.80 -570.184166 10743 4 2018-11-17 319.20 -809.813636 11075 68 2019-05-06 498.10 -1546.297500 10388 72 2017-12-19 1228.80 -358.864285 10720 61 2018-10-28 550.00 -144.744285 11052 34 2019-04-27 1332.00 -1164.397500 10457 39 2018-02-25 1584.00 -797.999166 10789 23 2018-12-22 3687.00 1567.833334 10434 24 2018-02-03 321.12 -1329.582352 10766 56 2018-12-05 2310.00 1015.105000 ...
नेस्टेड पंक्ति संख्या फ़ंक्शन का उपयोग करके, कार्य एक ही क्वेरी के साथ प्राप्त करने योग्य है, जैसे:
SELECT orderid, custid, orderdate, val,
val - AVG( CASE
WHEN ROW_NUMBER(FRAME_ROW) NOT IN
( ROW_NUMBER(BEGIN_PARTITION), ROW_NUMBER(END_PARTITION) ) THEN val
END )
OVER( PARTITION BY custid
ORDER BY orderdate, orderid
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS diff
FROM Sales.OrderValues; साथ ही, वर्तमान में समर्थित समाधान के लिए योजना में कम से कम एक प्रकार की आवश्यकता होती है, और डेटा पर एकाधिक पास की आवश्यकता होती है। नेस्टेड पंक्ति संख्या फ़ंक्शंस का उपयोग करने वाले समाधान में इंडेक्स ऑर्डर पर निर्भरता के साथ अनुकूलित होने की सभी संभावनाएं हैं, और डेटा पर कम संख्या में पास हैं। बेशक, यह कार्यान्वयन पर निर्भर है।
पंक्ति फ़ंक्शन पर नेस्टेड value_of अभिव्यक्ति
पंक्ति फ़ंक्शन पर नेस्टेड value_of अभिव्यक्ति आपको विंडो एग्रीगेट फ़ंक्शन के तर्क में पहले बताए गए समान रणनीतिक पंक्ति मार्करों पर एक अभिव्यक्ति के मूल्य के साथ बातचीत करने में सक्षम बनाती है। यहां इस फ़ंक्शन का सिंटैक्स दिया गया है:
<अभिव्यक्ति> का मान <पंक्ति मार्कर> [<डेल्टा>] [, <डिफ़ॉल्ट>] के साथ तर्क
>) OVER(<विनिर्देश>)
जैसा कि आप देख सकते हैं, आप पंक्ति मार्कर के संबंध में एक निश्चित नकारात्मक या सकारात्मक डेल्टा निर्दिष्ट कर सकते हैं, और वैकल्पिक रूप से एक डिफ़ॉल्ट मान प्रदान कर सकते हैं यदि कोई पंक्ति निर्दिष्ट स्थान पर मौजूद नहीं है।
जब आपको विंडोिंग तत्वों में विभिन्न बिंदुओं के साथ बातचीत करने की आवश्यकता होती है तो यह क्षमता आपको बहुत अधिक शक्ति प्रदान करती है। इस तथ्य पर विचार करें कि खिड़की के कार्यों के रूप में शक्तिशाली की तुलना उपश्रेणियों जैसे वैकल्पिक उपकरणों से की जा सकती है, जो खिड़की के कार्यों का समर्थन नहीं करते हैं, यह एक सहसंबंध की मूल अवधारणा है। CURRENT_ROW मार्कर का उपयोग करके आप बाहरी पंक्ति तक पहुँच प्राप्त करते हैं, और इस तरह सहसंबंधों का अनुकरण करते हैं। साथ ही आपको उन सभी लाभों का भी लाभ मिलता है जो विंडो फंक्शन सबक्वेरी की तुलना में करते हैं।
एक उदाहरण के रूप में, मान लें कि आपको Sales.OrderValues दृश्य को क्वेरी करने की आवश्यकता है, और प्रत्येक ऑर्डर के लिए उसकी कुछ विशेषताओं के साथ-साथ वर्तमान ऑर्डर मूल्य और ग्राहक औसत के बीच अंतर को वापस करना है, लेकिन उसी तिथि को दिए गए ऑर्डर को छोड़कर वर्तमान आदेश की तिथि। इसके लिए एक सहसंबंध के समान क्षमता की आवश्यकता होती है। पंक्ति फ़ंक्शन पर नेस्टेड value_of अभिव्यक्ति के साथ, CURRENT_ROW मार्कर का उपयोग करके, इसे आसानी से प्राप्त किया जा सकता है:
SELECT orderid, custid, orderdate, val,
val - AVG( CASE WHEN orderdate <> VALUE OF orderdate AT CURRENT_ROW THEN val END )
OVER( PARTITION BY custid ) AS diff
FROM Sales.OrderValues; यह क्वेरी निम्न आउटपुट उत्पन्न करने वाली है:
orderid custid orderdate val diff -------- ------- ---------- -------- ------------ 10248 85 2017-07-04 440.00 180.000000 10249 79 2017-07-05 1863.40 1280.452000 10250 34 2017-07-08 1552.60 -854.228461 10251 84 2017-07-08 654.06 -293.536666 10252 76 2017-07-09 3597.90 1735.092728 10253 34 2017-07-10 1444.80 -970.320769 10254 14 2017-07-11 556.62 -1127.988571 10255 68 2017-07-12 2490.50 617.913334 10256 88 2017-07-15 517.80 -176.000000 10257 35 2017-07-16 1119.90 -153.562352 ...
यदि आप सोच रहे हैं कि यह कार्य सहसंबद्ध उपश्रेणियों के साथ आसानी से प्राप्त किया जा सकता है, तो इस सरलीकृत मामले में आप सही होंगे। निम्न क्वेरी के साथ इसे प्राप्त किया जा सकता है:
SELECT O1.orderid, O1.custid, O1.orderdate, O1.val,
O1.val - ( SELECT AVG(O2.val)
FROM Sales.OrderValues AS O2
WHERE O2.custid = O1.custid
AND O2.orderdate <> O1.orderdate ) AS diff
FROM Sales.OrderValues AS O1; हालांकि, याद रखें कि एक सबक्वेरी डेटा के एक स्वतंत्र दृश्य पर काम करती है, जबकि एक विंडो फ़ंक्शन उस सेट पर संचालित होता है जो लॉजिकल क्वेरी प्रोसेसिंग चरण में इनपुट के रूप में प्रदान किया जाता है जो सेलेक्ट क्लॉज को हैंडल करता है। आमतौर पर, अंतर्निहित क्वेरी में अतिरिक्त तर्क होते हैं जैसे जॉइन, फ़िल्टर, ग्रुपिंग, और ऐसे। सबक्वेरी के साथ, आपको या तो एक प्रारंभिक सीटीई तैयार करने की जरूरत है, या सबक्वेरी में अंतर्निहित क्वेरी के तर्क को भी दोहराना होगा। विंडो फ़ंक्शन के साथ, किसी भी तर्क को दोहराने की कोई आवश्यकता नहीं है।
उदाहरण के लिए, मान लें कि आपको केवल शिप किए गए ऑर्डर (जहां शिप की गई तारीख न्यूल नहीं है) पर काम करना चाहिए था, जिसे कर्मचारी द्वारा नियंत्रित किया गया था। विंडो फ़ंक्शन के साथ समाधान को फ़िल्टर जोड़ने की आवश्यकता होती है जो केवल एक बार भविष्यवाणी करता है, जैसे:पी>
SELECT orderid, custid, orderdate, val,
val - AVG( CASE WHEN orderdate <> VALUE OF orderdate AT CURRENT_ROW THEN val END )
OVER( PARTITION BY custid ) AS diff
FROM Sales.OrderValues
WHERE empid = 3 AND shippeddate IS NOT NULL; यह क्वेरी निम्न आउटपुट उत्पन्न करने वाली है:
orderid custid orderdate val diff -------- ------- ---------- -------- ------------- 10251 84 2017-07-08 654.06 -459.965000 10253 34 2017-07-10 1444.80 531.733334 10256 88 2017-07-15 517.80 -1022.020000 10266 87 2017-07-26 346.56 NULL 10273 63 2017-08-05 2037.28 -3149.075000 10283 46 2017-08-16 1414.80 534.300000 10309 37 2017-09-19 1762.00 -1951.262500 10321 38 2017-10-03 144.00 NULL 10330 46 2017-10-16 1649.00 885.600000 10332 51 2017-10-17 1786.88 495.830000 ...
सबक्वेरी के साथ समाधान को फ़िल्टर को दो बार जोड़ना होगा—एक बार बाहरी क्वेरी में और एक बार सबक्वेरी में—जैसे:
SELECT O1.orderid, O1.custid, O1.orderdate, O1.val,
O1.val - ( SELECT AVG(O2.val)
FROM Sales.OrderValues AS O2
WHERE O2.custid = O1.custid
AND O2.orderdate <> O1.orderdate
AND empid = 3
AND shippeddate IS NOT NULL) AS diff
FROM Sales.OrderValues AS O1
WHERE empid = 3 AND shippeddate IS NOT NULL; यह या तो यह है, या एक प्रारंभिक सीटीई जोड़ रहा है जो सभी फ़िल्टरिंग और किसी भी अन्य तर्क का ख्याल रखता है। वैसे भी आप इसे देखें, सबक्वेरी के साथ, इसमें अधिक जटिलता परतें शामिल हैं।
नेस्टेड विंडो फ़ंक्शंस में अन्य लाभ यह है कि यदि हमारे पास टी-एसक्यूएल में उन लोगों के लिए समर्थन होता, तो RANGE विंडो फ्रेम यूनिट के लिए अनुपलब्ध पूर्ण समर्थन का अनुकरण करना आसान होता। RANGE विकल्प आपको डायनामिक फ़्रेम को परिभाषित करने में सक्षम बनाता है जो वर्तमान पंक्ति में ऑर्डरिंग मान से ऑफ़सेट पर आधारित होते हैं। उदाहरण के लिए, मान लें कि आपको Sales.OrderValues से प्रत्येक ग्राहक ऑर्डर के लिए गणना करने की आवश्यकता है, पिछले 14 दिनों के मूविंग एवरेज वैल्यू को देखते हैं। SQL मानक के अनुसार, आप इसे RANGE विकल्प और INTERVAL प्रकार का उपयोग करके प्राप्त कर सकते हैं, जैसे:
SELECT orderid, custid, orderdate, val,
AVG(val) OVER( PARTITION BY custid
ORDER BY orderdate
RANGE BETWEEN INTERVAL '13' DAY PRECEDING
AND CURRENT ROW ) AS movingavg14days
FROM Sales.OrderValues; यह क्वेरी निम्न आउटपुट उत्पन्न करने वाली है:
orderid custid orderdate val movingavg14days -------- ------- ---------- ------- --------------- 10643 1 2018-08-25 814.50 814.500000 10692 1 2018-10-03 878.00 878.000000 10702 1 2018-10-13 330.00 604.000000 10835 1 2019-01-15 845.80 845.800000 10952 1 2019-03-16 471.20 471.200000 11011 1 2019-04-09 933.50 933.500000 10308 2 2017-09-18 88.80 88.800000 10625 2 2018-08-08 479.75 479.750000 10759 2 2018-11-28 320.00 320.000000 10926 2 2019-03-04 514.40 514.400000 10365 3 2017-11-27 403.20 403.200000 10507 3 2018-04-15 749.06 749.060000 10535 3 2018-05-13 1940.85 1940.850000 10573 3 2018-06-19 2082.00 2082.000000 10677 3 2018-09-22 813.37 813.370000 10682 3 2018-09-25 375.50 594.435000 10856 3 2019-01-28 660.00 660.000000 ...
इस लेखन की तिथि पर, यह सिंटैक्स टी-एसक्यूएल में समर्थित नहीं है। यदि हमारे पास टी-एसक्यूएल में नेस्टेड विंडो फ़ंक्शंस के लिए समर्थन था, तो आप इस क्वेरी को निम्नलिखित कोड के साथ अनुकरण करने में सक्षम होंगे:
SELECT orderid, custid, orderdate, val,
AVG( CASE WHEN DATEDIFF(day, orderdate, VALUE OF orderdate AT CURRENT_ROW)
BETWEEN 0 AND 13
THEN val END )
OVER( PARTITION BY custid
ORDER BY orderdate
RANGE UNBOUNDED PRECEDING ) AS movingavg14days
FROM Sales.OrderValues; क्या पसंद नहीं है?
अपना वोट दें
मानक नेस्टेड विंडो फ़ंक्शन एक बहुत ही शक्तिशाली अवधारणा की तरह लगते हैं जो विंडोिंग तत्वों में विभिन्न बिंदुओं के साथ बातचीत करने में बहुत अधिक लचीलेपन को सक्षम बनाता है। मुझे काफी आश्चर्य है कि मुझे मानक के अलावा अन्य अवधारणा का कोई कवरेज नहीं मिल रहा है, और मुझे इसे लागू करने वाले कई प्लेटफॉर्म नहीं दिख रहे हैं। उम्मीद है कि यह लेख इस सुविधा के लिए जागरूकता बढ़ाएगा। अगर आपको लगता है कि इसे टी-एसक्यूएल में उपलब्ध कराना आपके लिए उपयोगी हो सकता है, तो अपना वोट डालना सुनिश्चित करें!