How to Aggregate 7 Days in Sql

How to Aggregate 7 Days in Sql

I was trying to aggregate a 7 days data for FY13 (starts on 10/1/2012 and ends on 9/30/2013) in SQL Server but so far no luck yet. Could someone please take a look. Below is my example data.

DATE       BREAD    MILK    
10/1/12    1        3
10/2/12    2        4
10/3/12    2        3
10/4/12    0        4
10/5/12    4        0
10/6/12    2        1
10/7/12    1        3
10/8/12    2        4
10/9/12    2        3
10/10/12   0        4
10/11/12   4        0
10/12/12   2        1
10/13/12   2        1

So, my desired output would be like:

DATE       BREAD    MILK
10/1/12    1        3
10/2/12    2        4
10/3/12    2        3
10/4/12    0        4
10/5/12    4        0
10/6/12    2        1
Total      11       15
10/7/12    1        3
10/8/12    2        4
10/9/12    2        3
10/10/12   0        4
10/11/12   4        0
10/12/12   2        1
10/13/12   2        1
Total      13       16

--------through 9/30/2013

Please note, since FY13 starts on 10/1/2012 and ends on 9/30/2012, the first week of FY13 is 6 days instead of 7 days.

I am using SQL server 2008.

3

5 Answers

You could add a new computed column for the date values to group them by week and sum the other columns, something like this:

SELECT DATEPART(ww, DATEADD(d,-2,[DATE])) AS WEEK_NO, 
       SUM(Bread) AS Bread_Total, SUM(Milk) as Milk_Total
FROM YOUR_TABLE
GROUP BY DATEPART(ww, DATEADD(d,-2,[DATE]))

Note: I used DATEADD and subtracted 2 days to set the first day of the week to Monday based on your dates. You can modify this if required.

Use option with GROUP BY ROLLUP operator

SELECT CASE WHEN DATE IS NULL THEN 'Total' ELSE CONVERT(nvarchar(10), DATE, 101) END AS DATE,
       SUM(BREAD) AS BREAD, SUM(MILK) AS MILK
FROM dbo.test54
GROUP BY ROLLUP(DATE),(DATENAME(week, DATE))

Demo on SQLFiddle

Result:

DATE        BREAD   MILK
10/01/2012  1       3
10/02/2012  2       4
10/03/2012  2       3
10/04/2012  0       4
10/05/2012  4       0
10/06/2012  2       1
Total       11      15
10/07/2012  1       3
10/08/2012  4       7
10/10/2012  0       4
10/11/2012  4       0
10/12/2012  2       1
10/13/2012  2       1
Total       13      16
2

You are looking for a rollup. In this case, you will need at least one more column to group by to do your rollup on, the easiest way to do that is to add a computed column that groups them into weeks by date.

Take a lookg at: Summarizing Data Using ROLLUP

Here is the general idea of how it could be done:

You need a derived column for each row to determine which fiscal week that record belongs to. In general you could subtract that record's date from 10/1, get the number of days that have elapsed, divide by 7, and floor the result.

Then you can GROUP BY that derived column and use the SUM aggregate function.

The biggest wrinkle is that 6 day week you start with. You may have to add some logic to make sure that the weeks start on Sunday or whatever day you use but this should get you started.

The WITH ROLLUP suggestions above can help; you'll need to save the data and transform it as you need.

The biggest thing you'll need to be able to do is identify your weeks properly. If you don't have those loaded into tables already so you can identify them, you can build them on the fly. Here's one way to do that:

CREATE TABLE #fy (fyear int, fstart datetime, fend datetime);
CREATE TABLE #fylist(fyyear int, fydate DATETIME, fyweek int);

INSERT INTO #fy
SELECT 2012, '2011-10-01', '2012-09-30'
UNION ALL
SELECT 2013, '2012-10-01', '2013-09-30';

INSERT INTO #fylist
        ( fyyear, fydate )

SELECT fyear, DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart)) AS fydate
FROM Common.NUMBERS
CROSS APPLY (SELECT * FROM #fy WHERE fyear = 2013) fy
WHERE fy.fend >= DATEADD(DAY, Number, DATEADD(DAY, -1, fy.fstart));

WITH weekcalc AS
(
    SELECT DISTINCT DATEPART(YEAR, fydate) yr, DATEPART(week, fydate) dt
    FROM #fylist

),
    ridcalc AS
(
    SELECT 
    ROW_NUMBER() OVER (ORDER BY yr, dt) AS rid, yr, dt
    FROM weekcalc
)   

UPDATE #fylist
SET fyweek = rid
FROM #fylist
JOIN ridcalc
    ON DATEPART(YEAR, fydate) = yr
    AND DATEPART(week, fydate) = dt;



 SELECT list.fyyear, list.fyweek, p.[date], COUNT(bread) AS Bread, COUNT(Milk) AS Milk
 FROM products p
 JOIN #fylist list 
    ON p.[date] = list.fydate
 GROUP BY list.fyyear, list.fyweek, p.[date] WITH ROLLUP;

The Common.Numbers reference above is a simple numbers table that I use for this sort of thing (goes from 1 to 1M). You could also build that on the fly as needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

David Miller
Author

David Miller

David Miller brings 15 years of experience in global economics, personal finance strategy, and market dynamics. He specializes in turning complex economic trends into actionable insights for everyday readers.