nam*_*ami 32 sql t-sql sql-server sql-server-2005
是否可以在sql中执行更新语句,但只有在更新不同时才更新?
例如
如果在数据库中, col1 = "hello"
update table1 set col1 = 'hello'
Run Code Online (Sandbox Code Playgroud)
不应该执行任何类型的更新
但是,如果
update table1 set col1 = "bye"
Run Code Online (Sandbox Code Playgroud)
这应该执行更新.
sll*_*sll 28
如果新值与DB中的值相同,则不要执行任何更新
WHERE col1 != @newValue
Run Code Online (Sandbox Code Playgroud)
(显然也应该有一些Id
字段来识别一行)
WHERE Id = @Id AND col1 != @newValue
Run Code Online (Sandbox Code Playgroud)
PS:最初你只想在值为'bye'的情况下进行更新,所以只需添加AND col1 = 'bye'
,但我觉得这是多余的,我只是想
Dud*_*001 24
在查询编译和执行期间,SQL Server不会花时间确定UPDATE语句是否实际更改任何值.它只是按预期执行写操作,即使没有必要.
在场景中
update table1 set col1 = 'hello'
Run Code Online (Sandbox Code Playgroud)
你可能会认为SQL不会做任何事情,但它会 - 它将执行所有必要的写入,就好像你实际上已经改变了值一样.对于物理表(或聚簇索引)以及在该列上定义的任何非聚集索引,都会发生这种情况.这会导致写入物理表/索引,重新计算索引和事务日志写入.使用大型数据集时,仅更新将接收更改的行具有巨大的性能优势.
如果我们想在不必要时避免这些写入的开销,我们必须设计一种方法来检查是否需要更新.检查更新需求的一种方法是添加类似"where col <>'hello'的内容.
update table1 set col1 = 'hello' where col1 <> 'hello'
Run Code Online (Sandbox Code Playgroud)
但是在某些情况下这不会很好,例如,如果要更新具有许多行的表中的多个列,并且这些行中只有一小部分实际上会更改其值.这是因为需要对所有这些列进行过滤,并且非等式谓词通常不能使用索引查找,以及如上所述的表和索引写入和事务日志条目的开销.
但是使用EXISTS子句和EXCEPT子句的组合有一个更好的选择.我们的想法是将目标行中的值与匹配源行中的值进行比较,以确定是否确实需要更新.查看下面的修改后的查询,并检查以EXISTS开头的附加查询过滤器.注意SELECT语句在EXISTS子句中没有FROM子句.这一部分特别重要,因为这只会在查询计划中增加额外的常量扫描和过滤操作(两者的成本都是微不足道的).所以你最终得到的是一个非常轻量级的方法,用于确定首先是否需要UPDATE,从而避免不必要的写入开销.
update table1 set col1 = 'hello'
/* AVOID NET ZERO CHANGES */
where exists
(
/* DESTINATION */
select table1.col1
except
/* SOURCE */
select col1 = 'hello'
)
Run Code Online (Sandbox Code Playgroud)
当您为具有文字值的表中的所有行更新一个值时,对于原始问题中的简单场景检查简单WHERE子句中的更新,这看起来过于复杂.但是,如果要更新表中的多个列,并且更新源是另一个查询并且您希望最小化写入和事务日志条目,则此方法非常有效.它也比使用<>测试每个字段更好.
一个更完整的例子可能是
update table1
set col1 = 'hello',
col2 = 'hello',
col3 = 'hello'
/* Only update rows from CustomerId 100, 101, 102 & 103 */
where table1.CustomerId IN (100, 101, 102, 103)
/* AVOID NET ZERO CHANGES */
and exists
(
/* DESTINATION */
select table1.col1
table1.col2
table1.col3
except
/* SOURCE */
select z.col1,
z.col2,
z.col3
from #anytemptableorsubquery z
where z.CustomerId = table1.CustomerId
)
Run Code Online (Sandbox Code Playgroud)
ype*_*eᵀᴹ 10
如果要'hello'
仅将字段更改为'bye'
,请使用以下命令:
UPDATE table1
SET col1 = 'hello'
WHERE col1 = 'bye'
Run Code Online (Sandbox Code Playgroud)
如果您只想更新它'hello'
,请使用:
UPDATE table1
SET col1 = 'hello'
WHERE col1 <> 'hello'
Run Code Online (Sandbox Code Playgroud)
有这种奇怪方法的原因吗?正如丹尼尔评论的那样,没有特别的收获 - 除非你有数千行col1='hello'
.是这样的吗?
这可以通过更新前触发器实现.在此触发器中,您可以将旧值与新值进行比较,如果没有差异则取消更新.但这会导致来电者网站出错.
我不知道,你为什么要这样做,但这里有几种可能性: