2013-10-23 131 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 
相關問題