SQL 更新 - 有没有更优雅、更有效的方法来做到这一点?

Posted

技术标签:

【中文标题】SQL 更新 - 有没有更优雅、更有效的方法来做到这一点?【英文标题】:SQL Update - Is there a more elegant and efficient way of doing this? 【发布时间】:2009-10-03 15:13:02 【问题描述】:

我有 3 个表 Site、Price 和 PriceMonth。网站有很多价格(加入 siteId)。 PriceMonth 保存一个由 Price 查询的日期(加入 PriceMonth)。

这个想法是在将网站创建为占位符时创建价格记录。

当用户单击视图中的价格行时 - 我只需要更新该年剩余时间和该月起的价格。

我已经为一个有效的存储过程编写了代码。请暂时忽略硬编码值。它可以工作,但它可以变得更简单、更高效吗?

代码:

DECLARE @startDate smallDateTime                  
DECLARE @roc decimal(5,2)
DECLARE @Lec decimal(5,2)
DECLARE @power decimal(5,2)

SET @roc =  (SELECT roc FROM [Price] WHERE siteId = 77 AND PriceMonthId = 527)
SET @lec = (SELECT lec FROM [Price] WHERE siteId = 77 AND PriceMonthId = 527)   
SET @power = (SELECT [power] FROM [Price] WHERE siteId = 77 AND PriceMonthId = 527) 
SET @startDate = (Select [month] FROM  [PriceMonth] WHERE PriceMonthId = 527) 

UPDATE 
    Price
SET 
    roc = @roc
,   lec = @lec
,   [power] = @power
FROM 
    Price
    INNER JOIN priceMonth pm ON price.priceMonthId = pm.priceMonthId

WHERE
   (DATEPART(mm,pm.[Month]) > DATEPART(mm,@startDate)   AND 
   (DATEPART(yy,pm.[Month]) = DATEPART(yy,@startDate))) AND
    price.SiteId = 77 

【问题讨论】:

您能解释一下为什么需要占位符吗?为什么不在拥有真实数据的情况下插入价格? 当然,这是业务的要求,因此他们不必逐年查看所有价格。我已要求更改此设置,但我不允许 - 所以简而言之,这并不重要 - 我需要它们。 【参考方案1】:

您可以将变量作为连接添加到查询中,如下所示:

UPDATE     p
SET         roc = sourcePrice.roc,   
            lec = sourcePrice.lec,   
            [power] = sourcePrice.[power]
FROM        Price p
            INNER JOIN [Price] sourcePrice
            on p.siteId = sourcePrice.siteId
            and sourcePrice.siteId = 527
            INNER JOIN priceMonth pm 
            ON price.priceMonthId = pm.priceMonthId
            INNER JOIN priceMonth sourcepm
            ON sourcepm.PriceMonthId = 527

WHERE   pm.[Month] > sourcepm.StartDate
AND     (DATEPART(yy,pm.[Month]) = DATEPART(yy,sourcepm.StartDate))) 
AND     price.SiteId = 77

另请注意,我已从您的一个日期比较中删除了该函数 - 这是为了让 SQL Server 可以使用可能在那里定义的任何索引来至少缩小值的范围。

【讨论】:

谢谢 Joon - 我收到以下错误:Msg 4104, Level 16, State 1, Line 1 无法绑定多部分标识符“price.priceMonthId”。消息 207,级别 16,状态 1,第 14 行无效的列名称“开始日期”。消息 207,级别 16,状态 1,第 15 行无效的列名称“开始日期”。 Msg 4104, Level 16, State 1, Line 15 无法绑定多部分标识符“price.SiteId”。【参考方案2】:

您可以使用多重赋值来为一个查询的结果设置多个变量。

SELECT top 1
  @roc = roc,
  @lec = lec,
  @power = power
FROM Price
WHERE siteId = 77 and pricemonthid = 527

小心这种技巧:

如果没有返回行,则变量保持不变(在这种情况下为 null)。 如果返回多行,则分配每一行 - 将最后一组值作为最终值。如果未指定排序,则 sql server 确定行的顺序,任何行都可以在最后。

您可以预先计算要更新的日期范围。这可能使日期索引很有用。

DECLARE @StartRange datetime, @EndRange datetime

SET @StartRange = DateAdd(mm, DateDiff(mm, @startDate, 0), 0)
SET @EndRange = DateAdd(yy, 1 + DateDiff(yy, @StartRange, 0), 0)

UPDATE...
WHERE @StartRange <= pm.Month AND pm.Month < @EndRange
  AND price.SiteId = 77

【讨论】:

谢谢 - 这看起来不错。特定应用程序的性能不是问题,但这是一种有用的技术。【参考方案3】:

关于占位符的要求,您始终可以使用 LEFT JOIN 和 COALESCE 来回退到上个月的价格。或者,安排一个任务,在每个月最后一天的午夜从上个月创建新月份的价格。

【讨论】:

以上是关于SQL 更新 - 有没有更优雅、更有效的方法来做到这一点?的主要内容,如果未能解决你的问题,请参考以下文章

如何使这个联合查询更有效率?

我目前正在检查 UIAlertController 是不是存在以确定正在使用的操作系统版本。有没有更有效的方法来做到这一点?

有没有更有效的方法来执行这个嵌套的 SQL 查询?

有没有更优雅的方式来编写这个 SQL 查询?

有没有更清洁的方法来做到这一点? (在 Qt C++ 中准备好的 SQL 查询)

此 SQL 查询是不是有更有效的替代方法?