假设MyTable的表结构(KEY, datafield1, datafield2…)

通常,我希望更新现有记录,或者插入不存在的新记录。

从本质上讲:

IF (key exists)
  run update command
ELSE
  run insert command

最好的写法是什么?


当前回答

MS SQL Server 2008引入了MERGE语句,我认为它是SQL:2003标准的一部分。正如许多人所表明的那样,处理一行情况并不是什么大问题,但当处理大型数据集时,就需要游标,随之而来的是所有性能问题。MERGE语句在处理大型数据集时将非常受欢迎。

其他回答

虽然现在评论这个有点晚了,但我想添加一个使用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;

做一个if存在…其他的……至少要做两个请求(一个检查,一个采取行动)。下面的方法在记录存在时只需要一个,如果需要插入则需要两个:

DECLARE @RowExists bit
SET @RowExists = 0
UPDATE MyTable SET DataField1 = 'xxx', @RowExists = 1 WHERE Key = 123
IF @RowExists = 0
  INSERT INTO MyTable (Key, DataField1) VALUES (123, 'xxx')

在SQL Server 2008中,您可以使用MERGE语句

你可以使用:

INSERT INTO tableName (...) VALUES (...) 
ON DUPLICATE KEY 
UPDATE ...

使用这个,如果已经有一个特定键的条目,那么它将更新,否则,它将插入。

如果执行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可能更可取。