2012-02-26 47 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