15

我想我在这里有一个艰难的... :(

我试图按月计算订单数,即使是零。这是问题查询:

SELECT datename(month, OrderDate) as Month, COUNT(OrderNumber) AS Orders
FROM OrderTable
WHERE OrderDate >= '2012-01-01' and OrderDate <= '2012-06-30'
GROUP BY year(OrderDate), month(OrderDate), datename(month, OrderDate)

我想要得到的是这样的:

Month            Orders
-----            ------
January          10
February         7
March            0
April            12
May              0
June             5

...但我的查询跳过了 3 月和 5 月的一行。我已经尝试过COALESCE(COUNT(OrderNumber), 0)ISNULL(COUNT(OrderNumber), 0)但我很确定分组导致它不起作用。

4

3 回答 3

27

此解决方案不需要您对可能需要的月份列表进行硬编码,您只需提供任何开始日期和任何结束日期,它就会为您计算月份边界。它在输出中包含年份,因此它将支持超过 12 个月,因此您的开始日期和结束日期可以跨越年份边界并且仍然正确排序并显示正确的月份年份。

DECLARE @StartDate SMALLDATETIME, @EndDate SMALLDATETIME;

SELECT @StartDate = '20120101', @EndDate = '20120630';

;WITH d(d) AS 
(
  SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0))
  FROM ( SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
    FROM sys.all_objects ORDER BY [object_id] ) AS n
)
SELECT 
  [Month]    = DATENAME(MONTH, d.d), 
  [Year]     = YEAR(d.d), 
  OrderCount = COUNT(o.OrderNumber) 
FROM d LEFT OUTER JOIN dbo.OrderTable AS o
  ON o.OrderDate >= d.d
  AND o.OrderDate < DATEADD(MONTH, 1, d.d)
GROUP BY d.d
ORDER BY d.d;
于 2012-07-14T01:33:03.563 回答
4

由于您的查询无法猜测您想要的月份,因此您需要将想要存储的月份存储在某个地方,将它们与您的表连接起来,然后进行分组。就像是:

;With Months (Month) 
AS
(

    select 'January' as Month
    UNION
    select 'February' as Month
    UNION
    select 'March' as Month
    UNION
    select 'April' as Month
    UNION
    select 'May' as Month
    UNION
    select 'June' as Month
    UNION
    select 'July' as Month
    UNION
    select 'August' as Month
    UNION
    select 'September' as Month
    UNION
    select 'October' as Month
    UNION
    select 'November' as Month
    UNION
    select 'December' as Month

)
--Also you could have them in a "Months" Table

然后就是JOIN这张桌子和你的桌子:

   Select 
    SELECT datename(month, OrderDate) as Month, COUNT(OrderNumber) 
    FROM Months T1
    LEFT JOIN OrderTable T2 on datename(month, T2.OrderDate) = T2.Month
    WHERE (T2.OrderDate >= '2012-01-01' and T2.OrderDate <= '2012-06-30') 
OR T2.OrderDate IS NULL --So will show you the months with no rows
    GROUP BY year(T2.OrderDate), month(T2.OrderDate), datename(month, T2.OrderDate)

希望它有效!

于 2012-07-14T01:13:53.820 回答
1

这是使用递归 CTE 的一个:

declare @StartDate datetime = '2015-04-01';
declare @EndDate datetime = '2015-06-01';

-- sample data
declare @orders table (OrderNumber int, OrderDate datetime);
insert into @orders
select 11, '2015-04-02'
union all
select 12, '2015-04-03'
union all
select 13, '2015-05-03'
;

-- recursive CTE
with dates
as (
    select @StartDate as reportMonth
    union all
    select dateadd(m, 1, reportMonth)
    from dates
    where reportMonth < @EndDate
    )
select 
    reportMonth,
    Count = count(o.OrderNumber)
from dates
left outer join @orders as o 
    on o.OrderDate >= reportMonth
    and o.OrderDate < dateadd(MONTH, 1, reportMonth)
group by 
    reportMonth
option (maxrecursion 0);
;
于 2015-07-10T09:13:24.697 回答