2012-07-14 4 views
10

私はここにタフなものを持っていると思うことで、グループ内の欠落ヶ月を含め、ゼロここで、問題のクエリです:。は、ときに私がしても、月ごとの注文数を取得しようとしています</p> <p>:(...クエリ

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月と月の行をスキップし、私はCOALESCE(COUNT(OrderNumber), 0)ISNULL(COUNT(OrderNumber), 0)を試みたが、私はかなり確信しています。グループ分けはcaそれを使って働かないでください。

+3

それは 'OrderTable'は3月か月のためのレコードを持っていないようなので、一人でこの表から選択するものを数ヶ月のために結果を返すことはできませんに見えます。考えられる回避策:データベースに日付のマスター表がある場合は、それを活用することも、日付の独自の表を作成することもできます。 –

+1

@andyholadayが言ったように、1月〜12月のルックアップテーブルを作成し、左の結合を行うと、不足した月が得られます。 – kd7

答えて

21

このソリューションでは、必要な月のリストをハードコードする必要はありません。開始日と終了日を指定するだけで、月の境界が計算されます。これには出力の年が含まれ、12ヶ月以上をサポートし、開始日と終了日が1年の境界を越えて正しく注文され、正しい月が年になるようにします。ここで

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

うわー、印象的!あなたのSELECTは正しい注文数を返しませんでしたが、あなたのWITH部分はすごくうまくいったので、私はSELECTのサブクエリをWITHの結果に結びつけました。 –

+0

ありがとう、これはちょうど私がコードの偉大な部分を必要としています。 – Enzero

+0

このクエリはLINQでどのように見えますか?これは本当に私にとって悪夢ですT_T – Baby

1

クエリでは、あなたが望む月を推測できないので、あなたがどこかに保存したい月を持って、あなたのテーブルにそれらを結合してからグループ化する必要があります。あなたのテーブルと

;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) 

は、それが作品を願って!

+0

あなたの努力に感謝しますが、これは私のためには機能しませんでした。私はT1とT2が切り替わったと思っていましたが、私はそれを得ることができませんでした。 OrderTableから月の表に結合された結果がまだないため、どのように動作するのかわかりません。私がこのコンセプトを理解していれば、私は最高でも12ヶ月もかかるでしょう。それは私が探しているものではありません。 –

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); 
; 
関連する問題