Reputation: 265
I am searching for a way to sum columns by week. This is the initial table data.
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
and I want to add a row total to every end of the week like this:
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
TOTAL 27 4 7 4
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
TOTAL 28 2 4 9
I tried something similar the the code below but I have multiple columns to sum. Do you have other ideas, suggestions?
Also, grouping sets does not create a new row if there is no data for that week to sum (like 0 or NULL).
SELECT
YEAR(Date) AS OrderYear,
MONTH(Date) AS OrderMonth,
SUM(Col1) AS SumCol1
FROM tb
GROUP BY
GROUPING SETS
(
YEAR(Date), --1st grouping set
(YEAR(Date),MONTH(Date)) --2nd grouping set
)
Upvotes: 1
Views: 122
Reputation: 65373
You only need to add (DATEPART(wk, Date))
as aggregation rule after listing the other non-aggregated columns Date,Col1, Col2, Col3
. Btw, you do not need a WeekNo
column, since it could already be computer by use of (DATEPART(wk, Date))
.
So far so good, but ordering is such a daunting task as returning null values for WeekNo column for subtotal. I used two analytic functions ( ROW_NUMBER()
and FISRT_VALUE()
to overcome this problem ) :
SELECT COALESCE(Date,'TOTAL') As Date,
DATEPART(wk, Date) AS WeekNo,
SUM(Col1) AS Col1,
SUM(Col2) AS Col2,
SUM(Col3) AS Col3
FROM tb
GROUP BY GROUPING SETS ( ( Date,Col1, Col2, Col3 ),
(DATEPART(wk, Date))
)
ORDER BY CASE WHEN DATEPART(wk, Date) IS NULL
THEN
ROW_NUMBER() OVER (PARTITION BY DATEPART(wk, Date)
ORDER BY COALESCE(Date,'TOTAL') )
ELSE
DATEPART(wk, Date) -
FIRST_VALUE(DATEPART(wk, Date))
OVER ( ORDER BY COALESCE(Date,'TOTAL') ) + 1
END,
DATEPART(wk, Date)
Upvotes: 2
Reputation: 4042
Is this what you are after?
My solution uses the built in with rollup
addition to the group by
clause.
-- create sample data
declare @data table
(
[Date] Date,
WeekNo int,
Col1 int,
Col2 int,
Col3 int
);
insert into @data ([Date], WeekNo, Col1, Col2, Col3) values
('2020-07-01', 27, 1, 4, 3),
('2020-07-04', 27, 3, 3, 1),
('2020-07-06', 28, 1, 1, 1),
('2020-07-11', 28, 1, 3, 8);
-- solution
select case when grouping(d.Date) = 0
then convert(nvarchar(10), d.Date) -- type conversion so all column values have the same type
else 'TOTAL'
end as 'Date',
d.WeekNo,
sum(d.Col1) as 'Col1',
sum(d.Col2) as 'Col2',
sum(d.Col3) as 'Col3'
from @data d
group by d.WeekNo, d.Date with rollup -- "roll up" the aggregations
having grouping(d.WeekNo) = 0; -- filter out aggregation across weeks
Gives me:
Date WeekNo Col1 Col2 Col3
---------- ----------- ----------- ----------- -----------
2020-07-01 27 1 4 3
2020-07-04 27 3 3 1
TOTAL 27 4 7 4
2020-07-06 28 1 1 1
2020-07-11 28 1 3 8
TOTAL 28 2 4 9
Upvotes: 3