【发布时间】:2020-01-13 21:27:11
【问题描述】:
我在处理一个查询时遇到了一些麻烦。它利用了子查询和附加连接,我确信有一种方法可以更好、更易读、更高效地构建它,可能使用 CTE,但我不确定如何。
这里是:我有一个包含库存历史的表和另一个包含项目价格历史的表。我需要使用当时的最新价格计算每个历史条目的库存价值。
为了这篇文章的目的,我稍微简化了表格,只使用了一个库存中的一个项目。库存表如下所示:
select *
from Temp.dbo.InvHist
order by Date
历史价格如下所示:
select *
from Temp.dbo.PriceHist
order by Date
为了获得每个库存日期的最新价格,我首先需要从价格表中获取正确的日期:
select
InvHist.Date
,InvHist.Item
,InvHist.Amount
,max(PriceHist1.Date) DatePrice
from Temp.dbo.InvHist
left join (
select PriceHist.Item, PriceHist.Date
from Temp.dbo.PriceHist
group by PriceHist.Item, PriceHist.Date
) PriceHist1 on InvHist.Item = PriceHist1.Item and PriceHist1.Date <= InvHist.Date
group by
InvHist.Date
,InvHist.Item
,InvHist.Amount
order by
InvHist.Date
最后我再次加入价格表,以获得可以计算股票价值的正确价格:
select
a.*
,b.Price
,a.Amount * b.Price InvValue
from (
select
InvHist.Date
,InvHist.Item
,InvHist.Amount
,max(PriceHist1.Date) DatePrice
from Temp.dbo.InvHist
left join (
select PriceHist.Item, PriceHist.Date
from Temp.dbo.PriceHist
group by PriceHist.Item, PriceHist.Date
) PriceHist1 on InvHist.Item = PriceHist1.Item and PriceHist1.Date <= InvHist.Date
group by
InvHist.Date
,InvHist.Item
,InvHist.Amount
) a
left join Temp.dbo.PriceHist b on a.Item = b.Item and a.DatePrice = b.Date
那么,有没有人知道如何以更高效、更优雅的方式获得这个结果?
【问题讨论】:
-
您的查询看起来不错。只有当您有一个多次使用的公共子查询或需要使用您的查询不使用也不需要的自引用查询(例如用于递归)时,CTE 才真正有用。对内部查询执行连接非常好,并且表明正确使用 SQL。
-
如果您的性能很差,这意味着您缺少索引或您的
STATISTICS对象已过期。您是否查看过查询执行计划?他们会告诉你为什么查询很慢。 -
@Dai 是正确的。但是,我倾向于将事物从子查询中移出并放入 CTE,因为它使我更容易测试以确保我实际上选择了我想要的东西。我也更容易考虑何时将其构建在 CTE 中,但我个人不知道性能差异是什么。
-
旁白:首先,避免使用premature optimization(参见performance rant。)。如果存在性能问题,请查看实际执行计划以找到瓶颈。
-
CTE 在很大程度上是“语法糖”,不会影响性能。在绝大多数情况下,将子选择转换为 CTE 后,查询计划将完全相同。如果您尝试优化查询的性能,CTE 不是您的答案。如果您正在针对可读性、可维护性和可测试性进行优化,那么 CTE 非常棒。
标签: sql-server tsql common-table-expression inventory-management