CYMR0
CYMR0

Reputation: 566

Summarise by week, even for empty rows

I want to summarise the sum of sales.quantity by week, and to show the week number even if there are no sales.

I have setup a weeks table with 1-54 in there to use an outer join to force all week numbers to come through, but it isn't working. It misses out weeks where there have been no sales.

My query is:

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks LEFT OUTER JOIN 
     sales ON Weeks.WeekNum = DATEPART(week, sales.transDate)
WHERE (sales.transDate BETWEEN @fromDate AND @toDate)
GROUP BY Weeks.WeekNum

ANY help would be greatly received... it's probably something stupid that I've done!

Upvotes: 2

Views: 2045

Answers (4)

Igor Borisenko
Igor Borisenko

Reputation: 3866

As @msmucker0527 wrote get rid of WHERE (sales.transDate BETWEEN @fromDate AND @toDate). You can do it also this way:

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks W  
     LEFT JOIN sales S ON W.WeekNum = DATEPART(week, S.transDate)
            AND S.transDate BETWEEN @fromDate AND @toDate)
GROUP BY W.WeekNum

Also, this WHERE (sales.transDate BETWEEN @fromDate AND @toDate) guarantee the Index Scan of Sales table which can greatly slow down your query.
You'd better include columns WeekFirstDate datetime and WeekLastDate datetime into Weeks table and CREATE NONCLUSTERED INDEX IX_Name ON Sales (TransDate) INCLUDE (quantity). In this case your query can be changed this way:

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks W  
     LEFT JOIN sales S ON S.transDate>=W.WeekFirstDate
                          AND S.transDate<=W.WeekLastDate
                          AND S.transDate BETWEEN @fromDate AND @toDate)
GROUP BY W.WeekNum

Upvotes: 1

user359040
user359040

Reputation:

Try this:

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks 
LEFT JOIN sales 
       ON Weeks.WeekNum = DATEPART(week, sales.transDate) and
          sales.transDate BETWEEN @fromDate AND @toDate
WHERE Weeks.WeekNum BETWEEN DATEPART(week, @fromDate) AND 
                            DATEPART(week, @toDate)
GROUP BY Weeks.WeekNum

Upvotes: 1

UnhandledExcepSean
UnhandledExcepSean

Reputation: 12804

I prefer this method versus a sub-select

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks
LEFT OUTER JOIN  sales ON (Weeks.WeekNum = DATEPART(week, sales.transDate) AND sales.transDate BETWEEN @fromDate AND @toDate)
GROUP BY Weeks.WeekNum

Upvotes: 1

Matt Smucker
Matt Smucker

Reputation: 5244

The where clause WHERE (sales.transDate BETWEEN @fromDate AND @toDate) will remove any weeks without sales. You'll likely need to do a subquery to pull the transactions and then join that to your weeks table.

SELECT Weeks.WeekNum, SUM(sales.quantity) AS sales
FROM Weeks LEFT OUTER JOIN 
 (
    SELECT *
    FROM sales 
    WHERE (sales.transDate BETWEEN @fromDate AND @toDate)
 ) sales
    ON Weeks.WeekNum = DATEPART(week, sales.transDate)
GROUP BY Weeks.WeekNum

Upvotes: 2

Related Questions