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 是不是存在以确定正在使用的操作系统版本。有没有更有效的方法来做到这一点?