Reputation: 343
Thank you in advance.
I have a table :
id|| Subject || Marks
1 || English || 10
2 || Maths || 30
3 || History || 50
4 || English || 70
5 || Maths || 80
6 || History || 90
7 || English || 100
8 || Maths || 130
9 || History || 150
I want to find the difference of sum in terms of max cumulative sum and minimum cumulative sum for each subject:
Example
Subject || Marks || Cumulative sum || Cumulative diff(max-min)
history || 50 || 50 ||
History || 90 || 140 ||
History || 150 || 290 || (290-50)=240
I am able to get the cumulative sum but unable to find the rest of the values:
select t1.id,t1.marks,sum(t2.marks) as sum1
from [NorthWind].[dbo].[Table_1] t1
inner join [NorthWind].[dbo].[Table_1] t2 on t1.id>=t2.id
group by t1.id,t1.marks
order by t1.id
Thank you.
Upvotes: 0
Views: 289
Reputation:
DECLARE @TempData AS TABLE
(
Id int,
Subject varchar(20),
Marks int
)
INSERT INTO @TempData
VALUES
( 1, 'English', 10),
( 2, 'Maths', 30),
( 3, 'History', 50),
( 4, 'English', 70),
( 5, 'Maths', 80),
( 6, 'History', 90),
( 7, 'English', 100),
( 8, 'Maths', 130),
( 9, 'History', 150 )
Declare @SelectSubject Varchar(20)='History' --SELECT your subject here like English,Maths,History
SELECT Subject
,Marks
,RunningTotal AS CumulativeSum
,CASE
WHEN Rno = 3
THEN Cumulativediff
ELSE ''
END AS Cumulativediff
FROM (
SELECT *
, (
MAX(RunningTotal) OVER (ORDER BY Subject)) - (MIN(RunningTotal) OVER (ORDER BY Subject)
) AS Cumulativediff
,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS Rno
FROM (
SELECT *
FROM (
SELECT ISNULL(Subject, 'GrandTotal') AS Subject
,ISNULL(CASt(Marks AS VARCHAR(10)), 'SubTotal') AS Marks
,SUM(Marks) OVER (
PARTITION BY Subject ORDER BY Id
) AS RunningTotal
FROM @TempData
) Dt
WHERE dt.Subject = @SelectSubject
) Dt2
) Final
Result:
Subject Marks CumulativeSum Cumulativediff
-----------------------------------------------
History 50 50 0
History 90 140 0
History 150 290 240
Upvotes: 1
Reputation: 8093
Try this
with tbl1 as (
select t.*
,sum(marks) over (partition by subject order by id) as cum_sum
,sum(marks) over (partition by subject order by id)
- min(marks) over (partition by subject order by id)
as diff
,row_number() over (partition by subject order by id desc) as rnk
from your_table t
)
select
id,Subject,Marks,cum_sum
,case when rnk=1 then diff else null end as cum_diff
from tbl1 t
order by subject,id;
Output:
+----+---------+-------+---------+----------+
| id | Subject | Marks | cum_sum | cum_diff |
+----+---------+-------+---------+----------+
| 1 | English | 10 | 10 | NULL |
| 4 | English | 70 | 80 | NULL |
| 7 | English | 100 | 180 | 170 |
| 3 | History | 50 | 50 | NULL |
| 6 | History | 90 | 140 | NULL |
| 9 | History | 150 | 290 | 240 |
| 2 | Maths | 30 | 30 | NULL |
| 5 | Maths | 80 | 110 | NULL |
| 8 | Maths | 130 | 240 | 210 |
+----+---------+-------+---------+----------+
Upvotes: 2
Reputation: 5148
You could use SUM() OVER()
like this
DECLARE @SampleData AS TABLE
(
Id int,
Subject varchar(20),
Marks int
)
INSERT INTO @SampleData
VALUES
( 1, 'English', 10),
( 2, 'Maths', 30),
( 3, 'History', 50),
( 4, 'English', 70),
( 5, 'Maths', 80),
( 6, 'History', 90),
( 7, 'English', 100),
( 8, 'Maths', 130),
( 9, 'History', 150 )
SELECT *,
sum(sd.Marks) OVER(PARTITION BY sd.Subject ORDER BY sd.Id) AS [Cumulative sum],
sum(sd.Marks) OVER(PARTITION BY sd.Subject) - FIRST_VALUE(sd.Marks) OVER(PARTITION BY sd.Subject ORDER BY sd.Id) AS [Cumulative diff(max-min)]
-- or try MIN(sd.Marks).....
FROM @SampleData sd
ORDER BY sd.Subject, sd.Id
Demo link: http://rextester.com/GAE89325
Upvotes: 1
Reputation: 39477
Try this using window functions.
You can use window sum to find cuml sum and then use max and min on that.
select subject,
cuml_marks,
max(cuml_marks) over (partition by subject)
- min(cuml_marks) over (partition by subject) as cuml_diff
from (
select subject,
sum(marks) over (
partition by subject order by id
) as cuml_marks
from t
) t;
Upvotes: 1