2012-07-14 30 views
10

Tôi nghĩ rằng tôi có một vấn đề khó ở đây ... :(Bao gồm tháng còn thiếu trong Nhóm By truy vấn

tôi đang cố gắng để có được một số thứ tự theo tháng, ngay cả khi không Dưới đây là các truy vấn vấn đề:.

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) 

Những gì tôi đang tìm kiếm để có được một cái gì đó như thế này:.

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

... nhưng truy vấn của tôi bỏ qua một hàng cho tháng Ba và tháng Năm tôi đã thử COALESCE(COUNT(OrderNumber), 0)ISNULL(COUNT(OrderNumber), 0) nhưng tôi khá chắc chắn nhóm là ca bằng cách đó không làm việc.

+3

Có vẻ như 'OrderTable' không có hồ sơ cho tháng ba hay tháng, vì vậy việc lựa chọn từ bảng này một mình không thể trở về Kết quả là những tháng đó. Các work-around có thể có: Nếu cơ sở dữ liệu của bạn có một bảng tổng thể các ngày bạn có thể tận dụng nó, hoặc bạn có thể tạo ra bảng ngày của riêng bạn khi đang bay. –

+1

Giống như @andyholaday đã nói - tạo bảng tra cứu với tháng 1 ... Tháng 12 và tham gia lại, và bạn sẽ nhận được những tháng còn thiếu. – kd7

Trả lời

21

Giải pháp này không yêu cầu bạn phải mã hóa cứng danh sách các tháng bạn muốn, tất cả những gì bạn cần làm là cung cấp ngày bắt đầu và ngày kết thúc bất kỳ và tính toán ranh giới tháng cho bạn. Nó bao gồm năm đầu ra để nó sẽ hỗ trợ hơn 12 tháng và để ngày bắt đầu và ngày kết thúc của bạn có thể vượt qua ranh giới một năm và vẫn đặt hàng chính xác và hiển thị đúng tháng năm.

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; 
+0

Wow, ấn tượng! SELECT của bạn không trả về số thứ tự chính xác, nhưng phần WITH của bạn đã làm việc tuyệt vời ... vì vậy tôi chỉ LEFT JOINED kết quả của WITH với SELECT của tôi như một truy vấn phụ và nó hoạt động tuyệt vời, năm và tất cả! –

+0

Cảm ơn bạn rất nhiều điều này chỉ là những gì tôi cần một đoạn mã tuyệt vời. – Enzero

+0

truy vấn này trông như thế nào trong LINQ? đây thực sự là một cơn ác mộng đối với tôi T_T – Baby

1

Vì truy vấn của bạn Chỉ không thể đoán tháng bạn muốn, bạn sẽ cần có các tháng bạn muốn lưu trữ ở đâu đó, nối chúng với bảng của bạn và sau đó nhóm. Cái gì như:

;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 

Sau đó, Chỉ cần JOIN bảng này với bảng của bạn:

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) 

Hy vọng nó hoạt động!

+0

Cảm ơn nỗ lực của bạn, nhưng điều này không hiệu quả với tôi. Tôi đã suy nghĩ T1 và T2 đã được chuyển xung quanh, nhưng tôi không thể có được nó. Tôi không thấy làm thế nào nó có thể làm việc anyway bởi vì vẫn không có kết quả từ từ OrderTable để tham gia bảng tháng để. Nếu tôi hiểu được khái niệm, tốt nhất là tôi sẽ nhận được tất cả 12 tháng, đó không phải là những gì tôi đang tìm kiếm. –

1

Đây là một cách sử dụng đệ quy 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); 
; 
Các vấn đề liên quan