【问题标题】:UPDATE if exists else INSERT in SQL Server 2008 [duplicate]如果存在则更新 SQL Server 2008 中的其他插入 [重复]
【发布时间】:2014-02-08 03:07:55
【问题描述】:

我想知道如何使用一条语句在 SQL Server 中使用 UPSERT 或换句话说 UPDATE if records exists Else enter new record 操作?

此示例显示了在 Oracle Here 中实现此目的的方法 但它使用Dual 表,而SQL Server 中不存在。

那么,任何 SQL Server 替代品(无存储过程)好吗?

【问题讨论】:

  • 此外,MS SQL Server 中没有dual。您可以简单地使用 SELECT 而不使用 FROM 子句。在 Oracle 中,必须使用 FROM 子句,而在 SQL Server 中则不然。
  • 同意重复,但请阅读所有答案的所有 cmets - 有些人比其他人有更好的建议,最高投票的答案并不总是最好的,而是那些是最长的。
  • 您要求声明;为什么要说“没有存储过程”?这么说的目的是什么?您知道存储过程本质上只是一个或多个 T-SQL 语句的包装器,对吧?如果有人确实为您提供了存储过程,您可以在 CREATE PROCEDURE 之后获取代码,瞧,您不再拥有过程......

标签: sql sql-server sql-server-2008


【解决方案1】:

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

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

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
  INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;

更多关于UPSERT 方法的信息在这里:

很多人会这样建议:​​

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 是一个单一的语句,但它仍然必须真正执行多个操作——即使它让你认为它没有。

【讨论】:

  • 是的,TRY-CATCH 方法是将异常处理作为流控制 - 不好。第一种方法很有趣 - 避免重复阅读的非常酷的方法。
  • 我能否使用SCOPE_IDENTITY() 来获取更新或插入行的ID? msdn.microsoft.com/en-us/library/ms190315.aspx
  • 在处理 TVP 时,您对不使用 MERGE 的建议是否有所改变?
  • @StingyJack 不,为什么?当存在我有充分理由在 some 情况下避免使用的语法时,我认为在 all 情况下使用替代方案会更好。例外情况很难记录,甚至更难阻止人们从中学习。
猜你喜欢
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
相关资源
最近更新 更多