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

SQL में नेस्टेड विंडो फ़ंक्शन

ISO/IEC 9075:2016 मानक (SQL:2016) नेस्टेड विंडो फ़ंक्शन नामक एक विशेषता को परिभाषित करता है। यह सुविधा आपको विंडो एग्रीगेट फ़ंक्शन के तर्क के रूप में दो प्रकार के विंडो फ़ंक्शंस को नेस्ट करने की अनुमति देती है। विचार यह है कि आप विंडोिंग तत्वों में रणनीतिक मार्करों पर या तो एक पंक्ति संख्या, या अभिव्यक्ति के मूल्य को संदर्भित करने की अनुमति दें। मार्कर आपको विभाजन में पहली या अंतिम पंक्ति, फ़्रेम में पहली या अंतिम पंक्ति, वर्तमान बाहरी पंक्ति और वर्तमान फ़्रेम पंक्ति तक पहुँच प्रदान करते हैं। यह विचार बहुत शक्तिशाली है, जिससे आप अपने विंडो फ़ंक्शन के भीतर फ़िल्टरिंग और अन्य प्रकार के जोड़तोड़ को लागू कर सकते हैं जो कभी-कभी अन्यथा हासिल करना मुश्किल होता है। आप RANGE-आधारित फ़्रेम जैसी अन्य सुविधाओं का आसानी से अनुकरण करने के लिए नेस्टेड विंडो फ़ंक्शंस का भी उपयोग कर सकते हैं। यह सुविधा वर्तमान में टी-एसक्यूएल में उपलब्ध नहीं है। मैंने नेस्टेड विंडो फ़ंक्शंस के लिए समर्थन जोड़कर SQL सर्वर को बेहतर बनाने के लिए एक सुझाव पोस्ट किया। अगर आपको लगता है कि यह सुविधा आपके लिए फायदेमंद हो सकती है तो अपना वोट जोड़ना सुनिश्चित करें।

नेस्टेड विंडो फंक्शन किस बारे में नहीं हैं

इस लेखन की तारीख में, वास्तविक मानक नेस्टेड विंडो फ़ंक्शंस के बारे में बहुत अधिक जानकारी उपलब्ध नहीं है। जो चीज इसे कठिन बनाती है, वह यह है कि मुझे अभी तक इस सुविधा को लागू करने वाले किसी भी प्लेटफॉर्म के बारे में पता नहीं है। वास्तव में, नेस्टेड विंडो फ़ंक्शंस के लिए एक वेब खोज चलाने से विंडोड एग्रीगेट फ़ंक्शंस के भीतर नेस्टिंग ग्रुपेड एग्रीगेट फ़ंक्शंस के बारे में अधिकतर कवरेज और चर्चा मिलती है। उदाहरण के लिए, मान लें कि आप TSQLV5 नमूना डेटाबेस में Sales.OrderValues ​​दृश्य को क्वेरी करना चाहते हैं, और प्रत्येक ग्राहक और ऑर्डर तिथि, ऑर्डर मानों का दैनिक कुल, और वर्तमान दिन तक चलने वाले कुल के लिए वापस लौटना चाहते हैं। इस तरह के कार्य में समूहीकरण और विंडोिंग दोनों शामिल हैं। आप ग्राहक आईडी और ऑर्डर तिथि के आधार पर पंक्तियों को समूहित करते हैं, और ऑर्डर मानों के समूह योग के शीर्ष पर एक रनिंग योग लागू करते हैं, जैसे:

  USE TSQLV5; -- http://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 अभिव्यक्ति हैं।

नेस्टेड पंक्ति संख्या फ़ंक्शन

नेस्टेड पंक्ति संख्या फ़ंक्शन आपको विंडोिंग तत्वों में रणनीतिक मार्करों की पंक्ति संख्या को संदर्भित करने की अनुमति देता है। यहाँ फ़ंक्शन का सिंटैक्स है:

(<ROW_NUMBER (<पंक्ति मार्कर>) के साथ तर्क>) ओवर (<विनिर्देश>)

आप जिन पंक्ति मार्करों को निर्दिष्ट कर सकते हैं वे हैं:

  • 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;

क्या पसंद नहीं है?

अपना वोट दें

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. NoSQL डेटाबेस में डेटा लचीलेपन को सीमित करना

  2. प्रदर्शन आश्चर्य और अनुमान :STRING_SPLIT ()

  3. एसक्यूएल तुलना ऑपरेटर

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

  5. डेटाबेस के प्रदर्शन में 400% तक सुधार करें