2012-03-15 137 views
2

我试图计算产品在一个月内的总销售额,但我希望它包含任何“空”月份(无销售),并且只选择最近12个月。SQL Server:计算包含空月份的月总销售额

这是我的代码到目前为止。

declare 
@ProductNo int 

set @ProductNo = 1234 

SELECT 
YEAR(o.OrderDate) as 'Year', MONTH(o.OrderDate) as 'Month', sum(Amount) as 'Units sold',[ProductNo] 

    FROM [OrderLine] ol 
    inner join [Order] o on ol.OrderNo = o.OrderNo 
    where ProductNo = @ProductNo 

    Group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate) 
    Order by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate) 

这将返回

Year Month Units sold 
2011 6  2 
2011 10  1 
2011 11  1 
2012 2  1 

但我想它返回。

Year Month Units sold 
2011 4  0 
2011 5  0 
2011 6  2 
2011 7  0 
2011 8  0  
2011 9  0 
2011 10  1 
2011 11  1 
2011 12  0 
2012 1  0 
2012 2  2 
2012 3  0 

我使用SQL Server 2008 R2 SP1

+0

可能重复:http://stackoverflow.com/questions/9691824/handling-non-existent-values-in-sql-query-expression-for-ssrs-图表/ 9692399#9692399 – 2012-03-15 07:49:17

+1

真的不喜欢创建一个额外的表只是为了持有几个月的想法。 – gulbaek 2012-03-15 07:53:08

+0

你可以做的是创建一个表值函数来返回给定开始和结束日期的月份表。您可以分别使用MIN(OrderDate)和MAX(OrderDate)。我们在环境中使用类似的东西。 – tobias86 2012-03-15 07:55:59

回答

2

我之前,我知道你有日历表进行。我使用master.dbo.spt_values连续生成了12个月(包括当前)。

declare @ProductNo int 

    set @ProductNo = 1234 

select MONTH(d.date), YEAR(d.date), isnull(t.amnt, 0) as [Units sold] from (
    SELECT 
     YEAR(o.OrderDate) as 'Year', 
     MONTH(o.OrderDate) as 'Month', 
     sum(Amount) as amnt, 
     [ProductNo] 
    FROM [OrderLine] ol 
    inner join [Order] o on ol.OrderNo = o.OrderNo 
    where ProductNo = @ProductNo 
    group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate) 
) t 
right join (
    select dateadd(mm, -number, getdate()) as date 
    from master.dbo.spt_values 
    where type = 'p' and number < 12 
) d on year(d.date) = t.[year] and month(d.date) = t.[month] 
order by YEAR(d.date), MONTH(d.date) 
+0

获取此错误。无法找到列“d”或用户定义的函数或聚集“d.year”,或名称不明确。你在哪里定义它? – gulbaek 2012-03-15 08:17:33

+0

感谢您的回答,我提交并编辑了您的答案,在那里我修改了它的工作方式,但认为您仍应该有信誉,指引我朝着正确的方向发展。 – gulbaek 2012-03-15 08:34:42

1

尝试:

;with CTE as 
(select 0 months_ago union all 
select months_ago - 1 months_ago from CTE where months_ago > -11), 
month_list as 
(select dateadd(MONTH, 
       months_ago, 
       dateadd(DAY, 
         1-datepart(DAY,getdate()), 
         cast(GETDATE() as DATE))) month_start 
from cte) 
SELECT YEAR(ml.start_date) as 'Year', 
     MONTH(ml.start_date) as 'Month', 
     sum(Amount) as 'Units sold',[ProductNo] 
FROM month_list ml 
left join [Order] o 
     on o.OrderDate >= ml.start_date and 
      o.OrderDate < dateadd(MONTH, 1, ml.start_date) 
left join [OrderLine] ol 
     on ol.OrderNo = o.OrderNo and ProductNo = @ProductNo 
Group by ProductNo, YEAR(ml.start_date), Month(ml.start_date) 
Order by ProductNo, YEAR(ml.start_date), Month(ml.start_date)