是否可以在sql中执行更新语句,但只有在更新不同时才更新?
例如
如果在数据库中,col1 = "hello"
update table1 set col1 = 'hello'
不应该执行任何类型的更新
然而,如果
update table1 set col1 = "bye"
应该执行更新。
答案 0 :(得分:25)
如果新值与DB中的新值相同,则不要执行任何更新
WHERE col1 != @newValue
(显然还应该有一些Id
字段来标识一行)
WHERE Id = @Id AND col1 != @newValue
PS:最初你只想在值为'bye'的情况下进行更新,所以只需添加AND col1 = 'bye'
,但我觉得这是多余的,我只是假设
答案 1 :(得分:17)
在查询编译和执行期间,SQL Server不会花时间确定UPDATE语句是否实际更改任何值。它只是按预期执行写入,即使没有必要。
在类似
的场景中update table1 set col1 = 'hello'
您可能认为SQL不会做任何事情,但它会 - 它将执行所有必要的写入,就像您实际更改了值一样。对于物理表(或聚簇索引)以及在该列上定义的任何非聚集索引,都会发生这种情况。这会导致写入物理表/索引,重新计算索引和事务日志写入。使用大型数据集时,仅更新将接收更改的行会带来巨大的性能优势。
如果我们想在不必要时避免这些写入的开销,我们必须设计一种方法来检查是否需要更新。检查是否需要更新的一种方法是添加类似“where col<> '你好'
update table1 set col1 = 'hello' where col1 <> 'hello'
但是在某些情况下这不会很好,例如,如果您要更新具有许多行的表中的多个列,并且这些行中只有一小部分实际上会更改其值。这是因为需要对所有这些列进行过滤,并且非等式谓词通常不能使用索引查找,并且表的开销也是如此。索引写入和事务日志条目如上所述。
但是使用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'
)
当您使用文字值更新表中所有行的一个值时,对于原始问题中的简单scenerio的简单WHERE子句中的更新检查,这看起来过于复杂。但是,如果要更新表中的多个列,并且更新源是另一个查询并且您希望最小化写入和事务日志条目,则此方法非常有效。它也比使用&lt;&gt;。
测试每个字段更好更完整的示例可能是
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
)
答案 2 :(得分:8)
如果您想将字段更改为'hello'
'bye'
,请使用此字段:
UPDATE table1
SET col1 = 'hello'
WHERE col1 = 'bye'
如果只想与'hello'
不同时更新,请使用:
UPDATE table1
SET col1 = 'hello'
WHERE col1 <> 'hello'
有这种奇怪方法的原因吗?正如丹尼尔评论的那样,没有特别的收获 - 除非你有col1='hello'
数千行。是这样的吗?
答案 3 :(得分:6)
这可以通过更新前触发器实现。 在此触发器中,您可以将旧值与新值进行比较,如果没有差异则取消更新。但这会导致来电者网站出现错误 我不知道,你为什么要这样做,但这里有几种可能性:
答案 4 :(得分:3)
CREATE OR REPLACE PROCEDURE stackoverflow([your_value] IN TYPE) AS
BEGIN
UPDATE [your_table] t
SET t.[your_collumn] = [your_value]
WHERE t.[your_collumn] != [your_value];
COMMIT;
EXCEPTION
[YOUR_EXCEPTION];
END stackoverflow;
答案 5 :(得分:1)
您需要在表格中使用唯一键id
(假设它的值为1)才能执行以下操作:
UPDATE table1 SET col1="hello" WHERE id=1 AND col1!="hello"
答案 6 :(得分:1)
旧问题,但没有一个答案正确处理null
值。
使用&lt;&gt;或者!=在比较差异值时会遇到麻烦,如果新值或旧值中存在潜在的空值,只有在更改时使用Postgres中的is distinct from
运算符才能安全更新。详细了解here
答案 7 :(得分:0)
如果没有声明变量或类似变量,则很难引用插入的硬编码值。如果这是你的目标,你应该考虑Daniel Hilgarth的解决方案。通常你会掌握价值。在这种情况下,你就是这样做的。
declare @t table (col1 varchar(10))
insert @t values ('hello')
insert @t values ('bye')
declare @newvalueforallrows varchar(10)
set @newvalueforallrows = 'hello'
update @t set col1 = @newvalueforallrows
where col1 <> @newvalueforallrows
-- 1 row updated
答案 8 :(得分:0)
我认为这应该为你做的伎俩...
create trigger [trigger_name] on [table_name]
for insert
AS declare @new_val datatype,@id int;
select @new_val = i.column_name from inserted i;
select @id = i.Id from inserted i;
update table_name set column_name = @new_val
where table_name.Id = @id and column_name != @new_val;
答案 9 :(得分:-1)
update table1 set col1 = 'bye'
WHERE col1 != 'hello'