2012-02-26 4 views
2

最後の5日間、3つの製品とその数量を日付別にグループ化して一覧表示する必要があります。このため私は以下のTSQLを使用しました。結果として 存在しないグループ明細カテゴリのゼロカウント

SELECT CONVERT(VARCHAR(10),WM_data,103) as Date, 
     Product = CASE 
        WHEN WM_Product = 1 THEN 'Product A' 
        WHEN WM_Product = 2 THEN 'Product B' 
        ELSE 'Product C' 
       END, 
     WM_qtd as Quantity 
    FROM Tb_InfoProduct 
GROUP BY CONVERT(VARCHAR(10),WM_data,103), WM_Product 
    HAVING CONVERT(VARCHAR(10),WM_data,103) > convert(VARCHAR(10),dateadd(dd, -5, getdate()),103) 
ORDER BY CONVERT(VARCHAR(10),WM_data,103), WM_Product 

は私が受け取る:

Date   Product  Quantity 
------------------------------------------------- 
16/02/2012 Product A 132 
16/02/2012 Product C  10 
17/02/2012 Product A 163 
17/02/2012 Product B  61 
17/02/2012 Product C  58 
18/02/2012 Product A  7 
18/02/2012 Product B  2 

しかし、私は必要があります。

Date  Product  Quantity 
------------------------------------------------- 
16/02/2012 Product A 132 
16/02/2012 Product B  0 -- This 
16/02/2012 Product C 10 
17/02/2012 Product A 163 
17/02/2012 Product B 61 
17/02/2012 Product C 58 
18/02/2012 Product A  7 
18/02/2012 Product B  2 
18/02/2012 Product C  0 -- This 

どのように私はこれを達成することができますか?

+0

。 –

+0

さて、WHERE句でフィルタリングする必要があります(文字列ではなく日付オブジェクトを使用します) – Leigh

答えて

1

まず第一に、あなたのクエリを持ついくつかの問題があります: - WM_qtd

  1. があなたのSELECT句はGROUP BYにも集計もない列が含まれています。あなたはSUM(WM_qtd)を意味しましたか?

  2. 通常、CONVERT(103)でフォーマットされた日付は、意味のある比較やソートができません。別の形式(112など)を使用するか、時間部分を削除する別の方法を使用して、後で(SELECT句の中か、まったくSQLにない)書式を適用することをお勧めします。

  3. HAVING句を使用してソースデータセットをフィルタリングしていますが、すべてのデータをプル、グループ化してからフィルタリングする必要があるため、非効率的です。この特定のケースでは、WHERE句を使用してデータをフィルタするほうがよいでしょう。あなたの質問のためとして今

...あなたが後にある結果セットは、基本的には、関連するすべての日付と(しゃれのためおっと、申し訳ありません)すべての関連製品のクロス積です。 Quantityのような追加情報が含まれています。

2つのリスト、日付、製品を取得してクロスジョインする必要がある場合は、結果セットをTb_InfoProductに外部結合し、日付と製品をグループ化して、クエリでは、GROUP BYSELECTの句が参照する日付と商品の列のみが、Tb_InfoProductテーブルのものではなく、それぞれの派生リストのものでなければなりません。

私が答えようとしているのは、あなたが要求しているTb_InfoProductのサブセットには、すべての日付と出力に存在する必要があるすべての製品が含まれていると仮定しています。特定の日付と異なる製品をTb_InfoProductサブセットから選択します。ここでは、その全体が近似解です:

SELECT 
    Date = CONVERT(VARCHAR(10), d.Date, 103), 
    Product = CASE p.WM_Product 
    WHEN 1 THEN 'Product A' 
    WHEN 2 THEN 'Product B' 
    ELSE  'Product C' 
    END, 
    Quantity = SUM(WM_qtd) 
FROM (
    SELECT DISTINCT Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0) 
    FROM Tb_InfoProduct 
    WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0) 
) d 
CROSS JOIN (
    SELECT DISTINCT WM_Product 
    FROM Tb_InfoProduct 
    WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0) 
) p 
LEFT JOIN (
    SELECT 
    Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0), 
    WM_Product 
    FROM Tb_InfoProduct 
    WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0) 
) i ON d.Date = i.Date AND p.WM_Product = i.WM_Product 
GROUP BY 
    d.Date, 
    p.WM_Product 
ORDER BY 
    d.Date, 
    p.WM_Product 

要求されたサブセットを使用すると、出力に含めることを好むだろういくつかの日付および/または製品を省略することができた場合、あなたは違った(複数可)のリストを構築する必要があります。たとえば、商品リストの場合はProducts参照表を使用することができます。日付については、 @OMG Ponies(この質問はあなたに役立つかもしれません:Get a list of dates between two dates using a function)によって提案されているように、指定された範囲の日付のリストを生成する必要があります。

0

SQL 2008を使用している場合:

あなたはその後、OUTERは、日付値にに参加することを、日付のリストを持っている(または生成)する必要が
SELECT table1.date, table2.productid, isnull(table3.total,0) total FROM 
--get the last 5 days 
(
select distinct date from mytable1 where date > getdate() - 5 
) table1 
--get the 3 products 
CROSS JOIN 
(
select productid from product where productid in (1,2,3) 
) table2 
OUTER APPLY (SELECT SUM(1) Total from YourTable 
    where yourtable.date = table1.date 
    and yourtable.productid = table2.productid) Table3 
関連する問題