2012-02-26 43 views
2

我需要查找過去五天內按日期分組的三種產品及其數量的列表。爲此,我使用了下面的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

你需要有(或產生)日期的列表,你再外連接上的日期值。 – 2012-02-26 02:58:20

+0

另外,您應該在'WHERE'子句中進行過濾(使用日期對象而不是字符串) – Leigh 2012-02-26 04:42:26

回答

1

首先,有一些問題與您的查詢:

  1. SELECT子句包含一列既不是在GROUP BY也不彙總 - WM_qtd。你的意思是SUM(WM_qtd),不是嗎?

  2. 通常,使用CONVERT(103)格式化的日期不能進行有意義的比較和排序。我建議你要麼使用不同的格式(如112),要麼使用不同的方法去除時間部分,稍後應用格式(僅在SELECT子句中,或者可能不在SQL中)。

  3. 您正在使用HAVING子句過濾源數據集,效率低下,因爲所有數據都必須進行拉取,分組並且只能進行過濾。在這種情況下,用WHERE條款過濾數據會更好。

現在爲你的問題......結果集你以後基本上所有相關的日期和所有相關產品(哎呀,對不起,雙關語)的跨產品。它只包含一些附加信息,如數量。

所以,你需要獲取兩個列表,日期和產品,跨加入他們的行列,那麼你可以外合併產生的設置爲Tb_InfoProduct和group by日期和產品,以獲得數 - 一樣的,你已經在做在您的查詢中,只有您的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:

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