我有点难过我会如何解决这个问题。
我有一个非常基本的查询,目前按年份和月份返回每种产品的销售额。 它按年/月分组,并总结数量。 这将为每个产品/年/月组合返回一行,其中有一个销售。
如果一个月没有销售,则没有数据。
我希望我的查询在我的日期范围内为每个年/月的每件商品返回一行数据,无论是否有实际订单。
如果没有订单,那么我可以为该产品/年/月返回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 :(得分: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
结果将是
另一种转折:
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
以下是sqlserver 2012及更高版本的工作方式,用于获取当月的最后一天:-
Select EOMONTH('2020-02-15')