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.
35 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 2You 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.