假设MyTable的表结构(KEY, datafield1, datafield2…)
通常,我希望更新现有记录,或者插入不存在的新记录。
从本质上讲:
IF (key exists)
run update command
ELSE
run insert command
最好的写法是什么?
假设MyTable的表结构(KEY, datafield1, datafield2…)
通常,我希望更新现有记录,或者插入不存在的新记录。
从本质上讲:
IF (key exists)
run update command
ELSE
run insert command
最好的写法是什么?
当前回答
虽然现在评论这个有点晚了,但我想添加一个使用MERGE的更完整的示例。
这样的Insert+Update语句通常被称为“Upsert”语句,可以在SQL Server中使用MERGE实现。
这里举了一个很好的例子: http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
上面还解释了锁定和并发场景。
我将引用同样的内容作为参考:
ALTER PROCEDURE dbo.Merge_Foo2
@ID int
AS
SET NOCOUNT, XACT_ABORT ON;
MERGE dbo.Foo2 WITH (HOLDLOCK) AS f
USING (SELECT @ID AS ID) AS new_foo
ON f.ID = new_foo.ID
WHEN MATCHED THEN
UPDATE
SET f.UpdateSpid = @@SPID,
UpdateTime = SYSDATETIME()
WHEN NOT MATCHED THEN
INSERT
(
ID,
InsertSpid,
InsertTime
)
VALUES
(
new_foo.ID,
@@SPID,
SYSDATETIME()
);
RETURN @@ERROR;
其他回答
如果执行UPDATE If -no-rows-updated then INSERT路由,考虑先执行INSERT以防止竞争条件(假设没有插入DELETE)
INSERT INTO MyTable (Key, FieldA)
SELECT @Key, @FieldA
WHERE NOT EXISTS
(
SELECT *
FROM MyTable
WHERE Key = @Key
)
IF @@ROWCOUNT = 0
BEGIN
UPDATE MyTable
SET FieldA=@FieldA
WHERE Key=@Key
IF @@ROWCOUNT = 0
... record was deleted, consider looping to re-run the INSERT, or RAISERROR ...
END
除了避免竞争条件之外,如果在大多数情况下记录已经存在,那么这将导致INSERT失败,浪费CPU。
在SQL2008以后使用MERGE可能更可取。
我尝试了下面的解决方案,它为我工作,当插入语句发生并发请求时。
begin tran
if exists (select * from table with (updlock,serializable) where key = @key)
begin
update table set ...
where key = @key
end
else
begin
insert table (key, ...)
values (@key, ...)
end
commit tran
在SQL Server 2008中,您可以使用MERGE语句
我通常会像其他几个帖子说的那样,先检查它是否存在,然后再做任何正确的路径。在这样做时,您应该记住的一件事是,sql缓存的执行计划对于一个路径或另一个路径可能不是最优的。我认为最好的方法是调用两个不同的存储过程。
FirstSP: If Exists Call SecondSP (UpdateProc) Else Call ThirdSP (InsertProc)
现在,我不经常听从自己的建议,所以对我的建议半信半疑。
做一个选择,如果你得到一个结果,更新它,如果没有,创建它。