संचयी राशि कैसे प्राप्त करें


186
declare  @t table
    (
        id int,
        SomeNumt int
    )

insert into @t
select 1,10
union
select 2,12
union
select 3,3
union
select 4,15
union
select 5,23


select * from @t

उपरोक्त चयन मुझे निम्नलिखित देता है।

id  SomeNumt
1   10
2   12
3   3
4   15
5   23

मैं निम्नलिखित कैसे प्राप्त करूं:

id  srome   CumSrome
1   10  10
2   12  22
3   3   25
4   15  40
5   23  63

5
टी-एसक्यूएल में रनिंग योग मुश्किल नहीं है, कई सही उत्तर हैं, उनमें से अधिकांश बहुत आसान हैं। जो आसान है (या इस समय भी संभव नहीं है) टी-एसक्यूएल में एक सच्चा प्रश्न लिखना है जो कि कुशल हो। वे सभी ओ (एन ^ 2) हैं, हालांकि वे आसानी से ओ (एन) हो सकते हैं, सिवाय इसके कि टी-एसक्यूएल इस मामले के लिए अनुकूलन नहीं करता है। आप कर्सर और / या जबकि लूप का उपयोग करके O (n) प्राप्त कर सकते हैं, लेकिन फिर आप कर्सर का उपयोग कर रहे हैं। ( Blech! )
RBarryYoung

जवाबों:


225
select t1.id, t1.SomeNumt, SUM(t2.SomeNumt) as sum
from @t t1
inner join @t t2 on t1.id >= t2.id
group by t1.id, t1.SomeNumt
order by t1.id

एसक्यूएल फिडेल उदाहरण

उत्पादन

| ID | SOMENUMT | SUM |
-----------------------
|  1 |       10 |  10 |
|  2 |       12 |  22 |
|  3 |        3 |  25 |
|  4 |       15 |  40 |
|  5 |       23 |  63 |

संपादित करें: यह एक सामान्यीकृत समाधान है जो अधिकांश db प्लेटफार्मों पर काम करेगा। जब आपके विशिष्ट प्लेटफ़ॉर्म (जैसे, गारेथ्स) के लिए एक बेहतर समाधान उपलब्ध है, तो इसका उपयोग करें!


12
@ फ्रेंकलिन केवल छोटे तालिकाओं के लिए कुशल है। लागत पंक्तियों की संख्या के वर्ग के समानुपाती होती है। SQL Server 2012 इसे और अधिक कुशलता से करने की अनुमति देता है।
मार्टिन स्मिथ

3
एफडब्ल्यूआईडब्ल्यू, मैंने डीबीए द्वारा ऐसा करने पर अपने पोर को मार दिया। मुझे लगता है कि इसका कारण यह वास्तव में महंगा है, वास्तव में जल्दी है। कहा जा रहा है कि, यह एक महान साक्षात्कार प्रश्न है, क्योंकि अधिकांश डेटा विश्लेषकों / वैज्ञानिकों को एक या दो बार इस समस्या को हल करना चाहिए था :)
बेन्दुंडी

@BenDundee सहमत - मैं सामान्यीकृत SQL समाधान प्रदान करता हूं जो अधिकांश db प्लेटफार्मों पर काम करेगा। हमेशा की तरह, जब वहाँ एक बेहतर दृष्टिकोण उपलब्ध है, उदाहरण के लिए, gareths, इसका उपयोग करें!
RedFilter

198

SQL सर्वर का नवीनतम संस्करण (2012) निम्नलिखित की अनुमति देता है।

SELECT 
    RowID, 
    Col1,
    SUM(Col1) OVER(ORDER BY RowId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col2
FROM tablehh
ORDER BY RowId

या

SELECT 
    GroupID, 
    RowID, 
    Col1,
    SUM(Col1) OVER(PARTITION BY GroupID ORDER BY RowId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col2
FROM tablehh
ORDER BY RowId

यह और भी तेज है। विभाजन संस्करण मेरे लिए 5 मिलियन पंक्तियों में 34 सेकंड में पूरा होता है।

पेसो के लिए धन्यवाद, जिन्होंने एसक्यूएल टीम थ्रेड पर टिप्पणी की और एक अन्य उत्तर में संदर्भित किया।


22
संक्षिप्तता के लिए, आप ROWS UNBOUNDED PRECEDINGइसके बजाय उपयोग कर सकते हैं ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
डैन

1
नोट: यदि आप जिस कॉलम को संचयी रूप से सम्‍मिलित करना चाहते हैं, वह स्‍वयं पहले से ही एक योग या गणना है, तो आप पूरी चीज़ को एक आंतरिक क्‍वेरी के रूप में लपेट सकते हैं या आप वास्‍तव में कर सकते हैं SUM(COUNT(*)) OVER (ORDER BY RowId ROWS UNBOUNDED PRECEDING) AS CumulativeSum। यह तुरंत मेरे लिए स्पष्ट नहीं था अगर यह काम करेगा, लेकिन इसने :-)
सिमोन_विवर

PostgreSQL में 8.4 के रूप में उपलब्ध है: postgresql.org/docs/8.4/sql-select.html
ADJenks

27

SQL सर्वर 2012 के लिए इसके बाद यह आसान हो सकता है:

SELECT id, SomeNumt, sum(SomeNumt) OVER (ORDER BY id) as CumSrome FROM @t

क्योंकि विंडो फ्रेम के लिए डिफ़ॉल्ट माध्यम से ORDER BYक्लॉज़ का SUMअर्थ है RANGE UNBOUNDED PRECEDING AND CURRENT ROW( https://msdn.microsoft.com/en-us/library/ms189461.aspx पर "सामान्य रिमार्क्स" )


13

एक सीटीई संस्करण, सिर्फ मनोरंजन के लिए:

;
WITH  abcd
        AS ( SELECT id
                   ,SomeNumt
                   ,SomeNumt AS MySum
             FROM   @t
             WHERE  id = 1
             UNION ALL
             SELECT t.id
                   ,t.SomeNumt
                   ,t.SomeNumt + a.MySum AS MySum
             FROM   @t AS t
                    JOIN abcd AS a ON a.id = t.id - 1
           )
  SELECT  *  FROM    abcd
OPTION  ( MAXRECURSION 1000 ) -- limit recursion here, or 0 for no limit.

यह दिखाता है:

id          SomeNumt    MySum
----------- ----------- -----------
1           10          10
2           12          22
3           3           25
4           15          40
5           23          63

12

सबसे पहले डमी डेटा -> के साथ एक टेबल बनाएं

Create Table CUMULATIVESUM (id tinyint , SomeValue tinyint)

**Now let put some data in the table**

Insert Into CUMULATIVESUM

Select 1, 10 union 
Select 2, 2  union
Select 3, 6  union
Select 4, 10 

यहाँ मैं एक ही तालिका में शामिल हो रहा हूँ (SELF Joining)

Select c1.ID, c1.SomeValue, c2.SomeValue
From CumulativeSum c1,  CumulativeSum c2
Where c1.id >= c2.ID
Order By c1.id Asc

परिणाम :

ID  SomeValue   SomeValue
1   10          10
2   2           10
2   2            2
3   6           10
3   6            2
3   6            6
4   10          10
4   10           2
4   10           6
4   10          10

यहाँ हम अब t2 के somevalue का योग करते हैं और हम as प्राप्त करते हैं

Select c1.ID, c1.SomeValue, Sum(c2.SomeValue) CumulativeSumValue
From CumulativeSum c1,  CumulativeSum c2
Where c1.id >= c2.ID
Group By c1.ID, c1.SomeValue
Order By c1.id Asc

SQL सर्वर 2012 और उससे अधिक के लिए (बहुत बेहतर प्रदर्शन)

Select c1.ID, c1.SomeValue, 
SUM (SomeValue) OVER (ORDER BY c1.ID )
From CumulativeSum c1
Order By c1.id Asc

वांछित परिणाम

ID  SomeValue   CumlativeSumValue
1   10          10
2   2           12
3   6           18
4   10          28

Drop Table CumulativeSum

Dummytable साफ़ करें


कृपया अपना उत्तर संपादित करें और कोड को पठनीय बनाने के लिए प्रारूपित करें
kleopatra

क्या होगा अगर mi "ID" मान दोहराया जाता है? (वे मेरी तालिका में प्राथमिक रूप से महत्वपूर्ण नहीं हैं) मैं इस मामले में इस प्रश्न को अनुकूलित करने में सक्षम नहीं हूं?
१14

AFAIK आपको संचयी राशि के लिए अद्वितीय आईडी की आवश्यकता है, और आप इसे row_number का उपयोग करके प्राप्त कर सकते हैं। नीचे दिए गए उस कोड की जाँच करें: NewTBLWITHUNiqueID के रूप में (चयन करें row_number () द्वारा क्रम में (id, somevalue द्वारा) UniqueID, * CUMULATIVESUMwithoutPK से)
नीरज प्रसाद शर्मा

धन्यवाद @NeerajPrasadSharma, मैंने वास्तव में इसका उपयोग rank()करने के लिए खंड द्वारा एक और आदेश का उपयोग किया ।
pablete

5

देर से जवाब लेकिन एक और संभावना दिखा ...

संचयी योग पीढ़ी को CROSS APPLYतर्क के साथ और अधिक अनुकूलित किया जा सकता है।

की तुलना में बेहतर काम करता है INNER JOINऔर OVER Clauseजब वास्तविक क्वेरी योजना का विश्लेषण किया ...

/* Create table & populate data */
IF OBJECT_ID('tempdb..#TMP') IS NOT NULL
DROP TABLE #TMP 

SELECT * INTO #TMP 
FROM (
SELECT 1 AS id
UNION 
SELECT 2 AS id
UNION 
SELECT 3 AS id
UNION 
SELECT 4 AS id
UNION 
SELECT 5 AS id
) Tab


/* Using CROSS APPLY 
Query cost relative to the batch 17%
*/    
SELECT   T1.id, 
         T2.CumSum 
FROM     #TMP T1 
         CROSS APPLY ( 
         SELECT   SUM(T2.id) AS CumSum 
         FROM     #TMP T2 
         WHERE    T1.id >= T2.id
         ) T2

/* Using INNER JOIN 
Query cost relative to the batch 46%
*/
SELECT   T1.id, 
         SUM(T2.id) CumSum
FROM     #TMP T1
         INNER JOIN #TMP T2
                 ON T1.id > = T2.id
GROUP BY T1.id

/* Using OVER clause
Query cost relative to the batch 37%
*/
SELECT   T1.id, 
         SUM(T1.id) OVER( PARTITION BY id)
FROM     #TMP T1

Output:-
  id       CumSum
-------   ------- 
   1         1
   2         3
   3         6
   4         10
   5         15

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

4

Select *, (Select SUM(SOMENUMT) From @t S Where S.id <= M.id) From @t M


यह परिणाम प्राप्त करने का एक बहुत ही स्मार्ट तरीका है, और आप कई शर्तों को जोड़ सकते हैं।
RaRdEvA

@RadEvA यह प्रदर्शन के लिए बहुत अच्छा नहीं है, हालांकि, यह correlated subqueryपरिणाम सेट की हर एक पंक्ति के लिए चलता है, जो अधिक से अधिक पंक्तियों को स्कैन करता है क्योंकि यह जाता है। यह एक रनिंग टोटल नहीं रखता है और एक बार विंडो फ़ंक्शन की तरह डेटा को स्कैन कर सकता है।
दावोस

1
@Davos आप सही हैं, अगर आप इसका उपयोग करते हैं तो यह 100,000 से अधिक रिकॉर्ड धीमा हो जाता है।
RaRdEvA

2

इस उत्कृष्ट पोस्ट में बहुत तेज़ CTE कार्यान्वयन उपलब्ध है: http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx

इस धागे में समस्या इस तरह व्यक्त की जा सकती है:

    DECLARE @RT INT
    SELECT @RT = 0

    ;
    WITH  abcd
            AS ( SELECT TOP 100 percent
                        id
                       ,SomeNumt
                       ,MySum
                       order by id
               )
      update abcd
      set @RT = MySum = @RT + SomeNumt
      output inserted.*


2

आप प्रगतिशील गणना के लिए इस सरल क्वेरी का उपयोग कर सकते हैं:

select 
   id
  ,SomeNumt
  ,sum(SomeNumt) over(order by id ROWS between UNBOUNDED PRECEDING and CURRENT ROW) as CumSrome
from @t

1

तालिका बनने के बाद -

select 
    A.id, A.SomeNumt, SUM(B.SomeNumt) as sum
    from @t A, @t B where A.id >= B.id
    group by A.id, A.SomeNumt

order by A.id

1

ऊपर (पूर्व SQL12) हम इस तरह के उदाहरण देखते हैं: -

SELECT
    T1.id, SUM(T2.id) AS CumSum
FROM 
    #TMP T1
    JOIN #TMP T2 ON T2.id < = T1.id
GROUP BY
    T1.id

अधिक कुशल...

SELECT
    T1.id, SUM(T2.id) + T1.id AS CumSum
FROM 
    #TMP T1
    JOIN #TMP T2 ON T2.id < T1.id
GROUP BY
    T1.id

0

इसे इस्तेमाल करे

select 
    t.id,
    t.SomeNumt, 
    sum(t.SomeNumt) Over (Order by t.id asc Rows Between Unbounded Preceding and Current Row) as cum
from 
    @t t 
group by
    t.id,
    t.SomeNumt
order by
    t.id asc;

यह SQL Server 2012 और 2008 के साथ काम करता है, इसमें विंडो कार्यों के लिए सीमित समर्थन है।
पीटर स्मिट

0

इसे इस्तेमाल करे:

CREATE TABLE #t(
 [name] varchar NULL,
 [val] [int] NULL,
 [ID] [int] NULL
) ON [PRIMARY]

insert into #t (id,name,val) values
 (1,'A',10), (2,'B',20), (3,'C',30)

select t1.id, t1.val, SUM(t2.val) as cumSum
 from #t t1 inner join #t t2 on t1.id >= t2.id
 group by t1.id, t1.val order by t1.id

0

SQL सॉल्यूशन wich "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" को जोड़ती है और "SUM" ने वही किया जो मैं हासिल करना चाहता था। आपको बहुत - बहुत धन्यवाद!

अगर यह किसी की मदद कर सकता है, तो यहां मेरा मामला था। जब भी किसी निर्माता को "कुछ निर्माता" (उदाहरण) के रूप में पाया जाता है, तो मैं एक कॉलम में +1 करना चाहता था। यदि नहीं, तो कोई वेतन वृद्धि नहीं है, लेकिन पिछले वेतन वृद्धि का परिणाम है।

तो एसक्यूएल का यह टुकड़ा:

SUM( CASE [rmaker] WHEN 'Some Maker' THEN  1 ELSE 0 END) 
OVER 
(PARTITION BY UserID ORDER BY UserID,[rrank] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Cumul_CNT

मुझे कुछ इस तरह पाने की अनुमति दी:

User 1  Rank1   MakerA      0  
User 1  Rank2   MakerB      0  
User 1  Rank3   Some Maker  1  
User 1  Rank4   Some Maker  2  
User 1  Rank5   MakerC      2
User 1  Rank6   Some Maker  3  
User 2  Rank1   MakerA      0  
User 2  Rank2   SomeMaker   1  

ऊपर का स्पष्टीकरण: यह 0 के साथ "कुछ निर्माता" की गिनती शुरू करता है, कुछ निर्माता पाया जाता है और हम +1 करते हैं। उपयोगकर्ता 1 के लिए, मेकरसी पाया जाता है इसलिए हम +1 नहीं करते हैं, लेकिन इसके बजाय कुछ मेकर की वर्टिकल काउंट अगली पंक्ति तक 2 तक अटक जाती है। विभाजन उपयोगकर्ता द्वारा होता है इसलिए जब हम उपयोगकर्ता बदलते हैं, तो संचयी गणना शून्य पर वापस आ जाती है।

मैं काम पर हूं, मुझे इस जवाब पर कोई योग्यता नहीं चाहिए, बस धन्यवाद कहें और किसी में उसी स्थिति में होने पर अपना उदाहरण दें। मैं SUM और विभाजन को संयोजित करने की कोशिश कर रहा था लेकिन अद्भुत वाक्य रचना "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" ने काम पूरा कर दिया।

धन्यवाद! Groaker


0

निम्नलिखित क्वेरी का उपयोग करके किसी व्यक्ति के लिए किसी भी प्रकार के JOIN संचयी वेतन का उपयोग किए बिना:

SELECT * , (
  SELECT SUM( salary ) 
  FROM  `abc` AS table1
  WHERE table1.ID <=  `abc`.ID
    AND table1.name =  `abc`.Name
) AS cum
FROM  `abc` 
ORDER BY Name

0

पूर्व के लिए: यदि आपके पास दो स्तंभों वाली एक तालिका है, तो एक आईडी है और दूसरी संख्या है और संचयी योग का पता लगाना चाहता है।

SELECT ID,Number,SUM(Number)OVER(ORDER BY ID) FROM T
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.