2013-10-23 169 views
4

我有点难住,我可能会去做这件事。返回所有月份和年份之间的日期范围 - SQL

我有一个非常基本的查询,目前每个产品按年份和月份返回销售。 按年/月分组,并总结数量。 这对于每次销售的产品/年/月组合都会返回一行。

如果一个月没有销售,那么就没有数据。

我想让我的查询为我的日期范围内的每个年/月的每个产品返回一行数据,而不管是否实际上有订单。

如果没有订单,那么我可以为该产品/年/月返回0。

以下是我的示例查询。

Declare @DateFrom datetime, @DateTo Datetime 
Set @DateFrom = '2012-01-01' 
set @DateTo = '2013-12-31' 

select 
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth, 
variant_detail.vad_variant_code, 
sum(order_line_item.oli_qty_required) as 'TotalQty' 

From 
variant_Detail 
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id 
join order_header on order_header.oh_id = order_line_item.oli_oh_id 

Where 
(order_header.oh_datetime between @DateFrom and @DateTo) 

Group By 
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110), 
variant_detail.vad_variant_code 
+0

我认为你需要一个12个月的表,简单的int列和你加入你的查询。 – Mihai

+0

问题是我无法改变数据库来添加一个表来做到这一点。 – OWSam

+1

按照Mihai的建议,但不是创建一个真正的表,而是使用一个表变量:''declare @mytable table(id int,name varchar(20))''然后将名称插入表变量并将其加入到查询中。 – acfrancis

回答

4

感谢您的建议。

我设法让这个工作使用另一种方法。

Declare @DateFrom datetime, @DateTo Datetime 
Set @DateFrom = '2012-01-01' 
set @DateTo = '2013-12-31' 

select 
YearMonthTbl.YearMonth, 
orders.vad_variant_code, 
orders.qty 

From 
(SELECT Convert(CHAR(4),DATEADD(MONTH, x.number, @DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, @DateFrom),110) As YearMonth 
FROM master.dbo.spt_values x 
WHERE x.type = 'P'   
AND  x.number <= DATEDIFF(MONTH, @DateFrom, @DateTo)) YearMonthTbl 


left join 
    (select variant_Detail.vad_variant_code, 
    sum(order_line_item.oli_qty_required) as 'Qty', 
    Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth' 
    FROM order_line_item 
    join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id 
    join order_header on order_header.oh_id = order_line_item.oli_oh_id 
    Where 
    (order_header.oh_datetime between @DateFrom and @DateTo) 
    GROUP BY variant_Detail.vad_variant_code, 
    Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) 
    ) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth 
+0

+1一般来说,拉一个集合将比递归CTE更有效率。 [你也可能会发现这个博客系列有用](http://www.sqlperformance.com/generate-a-set-1)。 –

1

这是我放在一起。它肯定会需要一些调试,但我认为这会使您朝着正确的方向发展。我将这些查询分解成不同的部分,以便更容易阅读。希望这可以帮助。

DECLARE @dateFrom DATETIME, @dateTo DATETIME 

SELECT @dateFrom = MIN(oh_datetime) FROM order_header 
SELECT @dateTo = MAX(oh_datetime) FROM order_header 

;WITH 
y AS 
(
    SELECT YEAR(@dateFrom) AS [Year] 
    UNION ALL 
    SELECT [Year] + 1 
    FROM y 
    WHERE 
      [Year] < YEAR (GETDATE()) 
), 
m AS 
(
    SELECT 1 AS [Month] 
    UNION ALL 
    SELECT [Month] + 1 
    FROM m 
    WHERE 
      [Month] < 12 
), 
dates AS 
(
SELECT 
    CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth 
FROM 
    y CROSS JOIN m 
), 
qty AS 
(
SELECT 
    YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth, 
    v.vad_variant_code, 
    oli.oli_qty_required AS Qty 
FROM 
    variant_Detail AS v 
     INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id 
     INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id 
) 
SELECT 
    d.YearMonth, 
    qty.vad_variant_code, 
    SUM(qty.Qty) AS TotalQty 
FROM 
    dates AS d LEFT OUTER JOIN qty 
     ON d.YearMonth = qty.YearMonth 
GROUP BY 
    d.YearMonth, 
    qty.vad_variant_code 
相关问题