我正在尝试生成一份销售报告,其中列出了每个产品+给定月份的总销售额。它有点棘手,因为产品价格可能会在整个月内发生变化。例如:
此设置在数据库中表示如下:
Sales table Sale_ID ProductID Sale_Date 1 1 2009-01-01 2 1 2009-01-01 3 1 2009-01-02 ... 50 1 2009-01-15 51 1 2009-01-16 52 1 2009-01-17 ... 100 1 2009-01-31 Prices table Product_ID Sale_Date Price 1 2009-01-01 10.00 1 2009-01-16 15.00
如果在价格表中定义了价格,则会将其应用于使用给定SaleDate中给定ProductID销售的所有产品。
基本上,我正在寻找一个返回数据的查询,如下所示:
Desired output Sale_ID ProductID Sale_Date Price 1 1 2009-01-01 10.00 2 1 2009-01-01 10.00 3 1 2009-01-02 10.00 ... 50 1 2009-01-15 10.00 51 1 2009-01-16 15.00 52 1 2009-01-17 15.00 ... 100 1 2009-01-31 15.00
我有以下查询:
SELECT
Sale_ID,
Product_ID,
Sale_Date,
(
SELECT TOP 1 Price
FROM Prices
WHERE
Prices.Product_ID = Sales.Product_ID
AND Prices.Sale_Date < Sales.Sale_Date
ORDER BY Prices.Sale_Date DESC
) as Price
FROM Sales
这是有效的,但是有一个比嵌套的子选择更有效的查询吗?
在你指出在Sales表中包含“price”会更容易之前,我应该提到架构是由另一个供应商维护的,我无法更改它。如果重要,我正在使用SQL Server 2000。
答案 0 :(得分:2)
避免这些类型的相关子查询是很好的。这是针对此类案例的经典技巧。
SELECT Sale_ID, Product_ID, Sale_Date, p1.Price FROM Sales AS s LEFT JOIN Prices AS p1 ON s.ProductID = p1.ProductID AND s.Sale_Date >= p1.Sale_Date LEFT JOIN Prices AS p2 ON s.ProductID = p2.ProductID AND s.Sale_Date >= p2.Sale_Date AND p2.Sale_Date > p1.Sale_Date WHERE p2.Price IS NULL -- want this one not to be found
在定价表上使用左外连接作为p2,并查找NULL记录,证明在p1中找到的匹配产品价格记录是销售日期或之前的最新记录。
(我会加入第一次价格匹配,但如果没有,那么很高兴让产品出现,所以你知道有问题。)
答案 1 :(得分:2)
如果您开始存储开始日期和结束日期,或创建包含开始日期和结束日期的视图(您甚至可以创建索引视图),那么您可以大大简化查询。 (如果您确定没有范围重叠)
SELECT
Sale_ID,
Product_ID,
Sale_Date,
Price
FROM Sales
JOIN Prices on Sale_date > StartDate and Sale_Date <= EndDate
-- careful not to use between it includes both ends
注意:
沿着这些方向的技术将允许您使用视图执行此操作。注意,如果你需要为视图编制索引,那么就必须对它进行相当多的调整..
create table t (d datetime)
insert t values(getdate())
insert t values(getdate()+1)
insert t values(getdate()+2)
go
create view myview
as
select start = isnull(max(t2.d), '1975-1-1'), finish = t1.d from t t1
left join t t2 on t1.d > t2.d
group by t1.d
select * from myview
start finish
----------------------- -----------------------
1975-01-01 00:00:00.000 2009-01-27 11:12:57.383
2009-01-27 11:12:57.383 2009-01-28 11:12:57.383
2009-01-28 11:12:57.383 2009-01-29 11:12:57.383
答案 2 :(得分:0)
您是否遇到了性能问题,或者您只是期待它们?我会像你一样完全实现这一点,我的双手是从你的架构修改的角度来看。
答案 3 :(得分:0)
我同意肖恩的意见。您编写的代码非常干净且易于理解。如果您遇到性能问题,请花费额外的精力使代码更快。否则,您无缘无故地使代码更复杂。当明智地使用时,嵌套的子选择非常有用。
答案 4 :(得分:-1)
Product_ID和Sale_Date的组合是您的外键。在Product_ID,Sale_Date上尝试选择加入。