返回所有月份&日期范围之间的年份 - SQL

时间:2013-10-23 11:49:29

标签: sql sql-server date

我有点难过我会如何解决这个问题。

我有一个非常基本的查询,目前按年份和月份返回每种产品的销售额。 它按年/月分组,并总结数量。 这将为每个产品/年/月组合返回一行,其中有一个销售。

如果一个月没有销售,则没有数据。

我希望我的查询在我的日期范围内为每个年/月的每件商品返回一行数据,无论是否有实际订单。

如果没有订单,那么我可以为该产品/年/月返回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

4 个答案:

答案 0 :(得分:11)

您可以使用CTE生成此内容。 您将找到有关本文的信息: http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/

特别是这段代码:

WITH CTE AS
(
    SELECT @start_date AS cte_start_date
    UNION ALL
    SELECT DATEADD(MONTH, 1, cte_start_date)
    FROM CTE
    WHERE DATEADD(MONTH, 1, cte_start_date) <= @end_date   
)
SELECT * 
FROM CTE

答案 1 :(得分: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

答案 2 :(得分: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

答案 3 :(得分:1)

如果您发现一年中的所有月份,这又是另一回事

;WITH DateYear AS (
    SELECT 0 AS num
    UNION ALL
    SELECT num + 1 FROM DateYear
    WHERE num < 11
)
Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from 
(SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017'))  AS FirstDateOfTheMonth, num from DateYear)
cte

结果将是

enter image description here

另一种转折:

Declare @dateFrom datetime ='2019-03-21', @dateTo datetime ='2019-12-31'
;WITH CTE AS
(
    SELECT @dateFrom AS cte_start_date
    UNION ALL
    SELECT DATEADD(MONTH, 1, cte_start_date)
        FROM CTE
        WHERE ( DATEADD(MONTH, 1, cte_start_date) <=  EOMONTH( @dateTo)   ) 
        --or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, @dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, @dateTo) ) )
)
SELECT * 
FROM CTE

enter image description here

以下是sqlserver 2012及更高版本的工作方式,用于获取当月的最后一天:- Select EOMONTH('2020-02-15')