我需要查找过去五天按日期分组的三种产品及其数量的清单。为此,我使用了下面的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 :(得分:1)
首先,您的查询存在一些问题:
您的SELECT
子句包含的列既不在GROUP BY
也不在聚合 - WM_qtd
。你的意思是SUM(WM_qtd)
,不是吗?
通常,使用CONVERT(103)
格式化的日期无法进行有意义的比较或排序。我建议您使用不同的格式(如112
)或使用不同的方法删除时间部分并稍后应用格式(仅在SELECT
子句中,或者可能不是在SQL中)。
您正在使用HAVING
子句过滤源数据集,这是低效的,因为所有数据都必须被提取,分组,然后才会被过滤。在这种特殊情况下,最好使用WHERE
子句过滤数据。
现在关于你的问题......你所追求的结果集基本上是所有相关日期和所有相关产品的交叉产品(哎呀,对不起双关语)。它只包含一些附加信息,如数量。
因此,您需要获取两个列表,日期和产品,交叉加入它们,然后您可以将结果集外部加入Tb_InfoProduct
并按日期和产品分组以获取数字 - 与您相同已经在您的查询中执行,只有GROUP BY
和SELECT
子句引用的日期和产品列必须是相应派生列表中的日期和产品列,而不是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)。< / p>
答案 1 :(得分: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