क्या एक सेलेक्ट स्टेटमेंट में "पिछली पंक्ति" मान को एक्सेस करने का कोई तरीका है?


93

मुझे तालिका की दो पंक्तियों के बीच एक स्तंभ के अंतर की गणना करने की आवश्यकता है। वहाँ किसी भी तरह से मैं सीधे SQL में यह कर सकता है? मैं Microsoft SQL Server 2008 का उपयोग कर रहा हूं।

मैं कुछ इस तरह की तलाश में हूँ:

SELECT value - (previous.value) FROM table

यह कल्पना करते हुए कि "पिछले" चर नवीनतम चयनित पंक्ति को संदर्भित करता है। निश्चित रूप से इस तरह के एक चयन के साथ कि मैं n-1 पंक्तियों के साथ तालिका में चयनित n पंक्तियों के साथ समाप्त हो जाऊंगा, यह शायद नहीं है, वास्तव में वास्तव में वही है जिसकी मुझे आवश्यकता है।

क्या यह किसी तरह से संभव है?


6
खैर अभी नए दर्शकों के लिए उपयोगी एक टिप्पणी के लिए जोड़ना। SQL 2012 में LAG और LEAD अब :) इस लिंक को देखें। blog.sqlauthority.com/2013/09/22/…
KD

जवाबों:


61

एसक्यूएल को ऑर्डर की धारणा में बनाया नहीं गया है, इसलिए आपको सार्थक होने के लिए कुछ कॉलम द्वारा ऑर्डर करने की आवश्यकता है। कुछ इस तरह:

select t1.value - t2.value from table t1, table t2 
where t1.primaryKey = t2.primaryKey - 1

यदि आप चीजों को ऑर्डर करना जानते हैं, लेकिन वर्तमान मूल्य को प्राप्त करने के तरीके को नहीं जानते हैं (जैसे, आप वर्णानुक्रम में ऑर्डर करना चाहते हैं) तो मुझे मानक एसक्यूएल में ऐसा करने का तरीका नहीं पता है, लेकिन अधिकांश एसक्यूएल कार्यान्वयन होगा इसे करने के लिए एक्सटेंशन।

यहां SQL सर्वर के लिए एक तरीका है जो काम करता है यदि आप पंक्तियों को आदेश दे सकते हैं जैसे कि प्रत्येक एक अलग है:

select  rank() OVER (ORDER BY id) as 'Rank', value into temp1 from t

select t1.value - t2.value from temp1 t1, temp1 t2 
where t1.Rank = t2.Rank - 1

drop table temp1

यदि आपको संबंधों को तोड़ने की आवश्यकता है, तो आप ORDER BY द्वारा आवश्यक के रूप में कई कॉलम जोड़ सकते हैं।


यह ठीक है, आदेश एक मुद्दा नहीं है, मैंने इसे सरल बनाने के लिए इसे उदाहरण से हटा दिया, मैं कोशिश करता हूं कि मैं इसे लागू करूं।
एडविन जार्विस

7
जो मानता है, कि प्राथमिक कुंजी अनुक्रमिक रूप से उत्पन्न होती है और पंक्तियों को कभी भी नष्ट नहीं किया जाता है और चयन में कोई अन्य आदेश खंड और नहीं होता है ... और
मार्टिनस्टेनर

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

आप सही हैं, मैंने SQL सर्वर एक्सटेंशन का उपयोग करके एक सुधार जोड़ा है।
रॉसफैब्रिकेंट

2
"यह ठीक है, आदेश एक मुद्दा नहीं है" के जवाब में ... फिर आप अपनी क्वेरी में सिर्फ एक मध्यस्थता मूल्य को घटाते क्यों नहीं हैं क्योंकि यदि आप आदेश नहीं मानते हैं तो आप क्या कर रहे हैं?
जॉन एफएक्स

79

अंतराल फ़ंक्शन का उपयोग करें :

SELECT value - lag(value) OVER (ORDER BY Id) FROM table

Ids के लिए उपयोग किए गए अनुक्रम मानों को छोड़ सकते हैं, इसलिए Id-1 हमेशा काम नहीं करता है।


1
यह PostgreSQL समाधान है। सवाल MSSQL के बारे में है। MSSQL का 2012 के संस्करण में ऐसा कार्य है ( msdn.microsoft.com/en-us/en-en/library/hh231256(v=sql.120).aspx )
क्रॉमस्टर

10
@KromStern न केवल PostgreSQL समाधान। SQL विंडो फ़ंक्शन SQL: 2003 मानक में पेश किए गए थे ।
हंस जिनजेल

LAG फ़ंक्शन तीन पैरामीटर ले सकता है LAG(ExpressionToSelect, NumberOfRowsToLag, DefaultValue):। अंतराल के लिए पंक्तियों की डिफ़ॉल्ट संख्या 1 है, लेकिन आप यह निर्धारित कर सकते हैं कि डिफ़ॉल्ट मूल्य का चयन तब करें जब आप सेट की शुरुआत में अंतराल के लिए संभव न हों।
vaindil

29

Oracle, PostgreSQL, SQL Server और कई और RDBMS इंजनों के विश्लेषणात्मक कार्य हैं जिन्हें कहा जाता है LAGऔरLEAD यह बहुत काम करते हैं।

2012 से पहले SQL सर्वर में आपको निम्नलिखित कार्य करने होंगे:

SELECT  value - (
        SELECT  TOP 1 value
        FROM    mytable m2
        WHERE   m2.col1 < m1.col1 OR (m2.col1 = m1.col1 AND m2.pk < m1.pk)
        ORDER BY 
                col1, pk
        )
FROM mytable m1
ORDER BY
      col1, pk

, कहाँ पे COL1 वह कॉलम है जिसे आप ऑर्डर कर रहे हैं।

एक सूचकांक होने पर (COL1, PK)इस क्वेरी में बहुत सुधार होगा।


14
SQL सर्वर 2012 में अब LAG और LEAD भी है।
एरिक

हाना SQL स्क्रिप्ट भी LAG और LEAD का समर्थन करती है।
mik

बस यहां पहुंचने वाले दर्शकों के लिए एक और टिप्पणी जोड़ने के लिए वह हाइव में कर रहा है। इसमें LAG और LEAD फ़ंक्शन भी हैं। यहाँ प्रलेखन: cwiki.apache.org/confluence/display/Hive/…
Jaime Caffarel

27
WITH CTE AS (
  SELECT
    rownum = ROW_NUMBER() OVER (ORDER BY columns_to_order_by),
    value
  FROM table
)
SELECT
  curr.value - prev.value
FROM CTE cur
INNER JOIN CTE prev on prev.rownum = cur.rownum - 1

यह सही ढंग से काम करता है अगर क्वेरी में कोई समूहीकरण नहीं है, लेकिन क्या होगा यदि हम केवल एक समूह के भीतर पिछले मूल्य से मूल्यों को घटाना चाहते हैं, वही एम्प्लॉईआईडी कहते हैं, तो हम ऐसा कैसे कर सकते हैं? Coz इसे चलाने से प्रत्येक समूह की शीर्ष 2 पंक्तियों के लिए काम करता है, न कि उस समूह की शेष पंक्तियों के लिए। इसके लिए, मैंने लूप में रहते हुए इस कोड का उपयोग किया, लेकिन यह बहुत धीमा प्रतीत होता है। इस परिदृश्य में कोई अन्य दृष्टिकोण? और वह भी केवल SQL Server 2008 में?
हेमंत सिसोदिया

10

बाईं ओर तालिका में शामिल हों, साथ में शामिल होने की स्थिति में काम किया ताकि पंक्ति को तालिका के सम्मिलित संस्करण में मिलान किया जा सके, एक पंक्ति पिछली है, आपके "पिछले" की विशेष परिभाषा के लिए।

अद्यतन: पहले मैं सोच रहा था कि आप सभी पंक्तियों को रखना चाहेंगे, NULLs के साथ उस स्थिति के लिए जहां कोई पिछली पंक्ति नहीं थी। इसे फिर से पढ़ते हुए आप बस इतना चाहते हैं कि पंक्तियाँ कम हो जाएं, इसलिए आपको एक बाएं जुड़ने के बजाय एक आंतरिक जुड़ाव चाहिए।


अपडेट करें:

Sql Server के नए संस्करणों में LAG और LEAD Windowing फ़ंक्शन भी हैं जिनका उपयोग इसके लिए भी किया जा सकता है।


3
select t2.col from (
select col,MAX(ID) id from 
(
select ROW_NUMBER() over(PARTITION by col order by col) id ,col from testtab t1) as t1
group by col) as t2

2

चयनित उत्तर केवल तभी काम करेगा जब अनुक्रम में कोई अंतराल न हो। हालाँकि यदि आप एक ऑटोजेनरेटेड आईडी का उपयोग कर रहे हैं, तो आवेषण के कारण अंतराल में होने की संभावना है जो वापस लुढ़का हुआ था।

यदि आपको अंतराल है तो यह विधि काम करना चाहिए

declare @temp (value int, primaryKey int, tempid int identity)
insert value, primarykey from mytable order by  primarykey

select t1.value - t2.value from @temp  t1
join @temp  t2 
on t1.tempid = t2.tempid - 1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.