如果SQL Server 2008中存在其他插入,则更新

如果SQL Server 2008中存在其他插入,则更新,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我想知道如何使用UPSERT,或者换言之updateif records existing,或者使用一条语句在SQL Server中输入新记录操作 此示例显示了在Oracle中实现此功能的方法 但它使用了SQL服务器中不存在的Dual表 那么,有没有SQL Server的替代方案(没有存储过程?很多人会建议您使用合并,但我提醒您不要这样做。默认情况下,它不会像保护多个语句那样保护您免受并发和竞争条件的影响,但它会引入其他危险: 即使有了这种“更简单”的语法,我仍然更喜欢这种方法(为了简洁起见,

我想知道如何使用
UPSERT
,或者换言之
updateif records existing,或者使用一条语句在SQL Server中输入新记录
操作

此示例显示了在Oracle中实现此功能的方法 但它使用了
SQL服务器中不存在的
Dual


那么,有没有SQL Server的替代方案(没有存储过程?

很多人会建议您使用
合并
,但我提醒您不要这样做。默认情况下,它不会像保护多个语句那样保护您免受并发和竞争条件的影响,但它会引入其他危险:

即使有了这种“更简单”的语法,我仍然更喜欢这种方法(为了简洁起见,省略了错误处理):

很多人会这样建议:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
  UPDATE ...
END
ELSE
BEGIN
  INSERT ...
END
COMMIT TRANSACTION;
BEGIN TRY
  INSERT ...
END TRY
BEGIN CATCH
  IF ERROR_NUMBER() = 2627
    UPDATE ...
END CATCH
但所有这些都是为了确保您可能需要读取表两次才能找到要更新的行。在第一个示例中,您将只需要定位行一次。(在这两种情况下,如果在初始读取中未找到行,则会发生插入。)

其他人会这样建议:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
  UPDATE ...
END
ELSE
BEGIN
  INSERT ...
END
COMMIT TRANSACTION;
BEGIN TRY
  INSERT ...
END TRY
BEGIN CATCH
  IF ERROR_NUMBER() = 2627
    UPDATE ...
END CATCH
但是,如果没有其他原因,让SQL Server捕获您本来可以防止的异常的成本要高得多,那么这是有问题的,除非在极少数情况下,几乎每次插入都会失败。我在这里也证明了这一点:


不确定你认为通过一句话你会得到什么;我认为你什么也得不到
MERGE
是一条语句,但它仍然必须真正执行多个操作,即使它让您认为它没有执行多个操作。

请检查这一点,而且,MS SQL Server中没有
dual
。您只需
选择
,无需
FROM
子句。在Oracle中,必须使用
FROM
子句,而在SQL Server中则不是这样。同意重复的内容,但请阅读所有答案上的所有注释-一些答案比其他答案有更好的建议,并且得票最多的答案并不总是最好的答案,而是最长的答案。您要求提供一份声明;为什么要说“无存储过程”?这样说的目的是什么?您知道存储过程本质上只是一个或多个T-SQL语句的包装器,对吗?如果有人向您提供了存储过程,您可以在创建过程之后再获取代码,瞧,您已经没有过程了……是的,
TRY
-
CATCH
方法作为流控制进行异常处理-不好。第一种方法很有趣-避免重复读取的非常酷的方法。我是否能够使用
SCOPE\u IDENTITY()
获取更新或插入行的ID?在处理TVP时,你不使用合并的建议改变了吗?@StingyJack不,为什么?在某些情况下,如果存在我有充分理由避免使用的语法,我认为最好在所有情况下都使用替代语法。例外情况很难记录,甚至更难阻止人们从中学习。