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

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

从本质上讲:

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

最好的写法是什么?


当前回答

您可以使用MERGE语句,此语句用于插入不存在的数据或更新存在的数据。

MERGE INTO Employee AS e
using EmployeeUpdate AS eu
ON e.EmployeeID = eu.EmployeeID`

其他回答

您可以使用这个查询。适用于所有SQL Server版本。它简单明了。但是您需要使用两个查询。如果不能使用MERGE,可以使用

    BEGIN TRAN

    UPDATE table
    SET Id = @ID, Description = @Description
    WHERE Id = @Id

    INSERT INTO table(Id, Description)
    SELECT @Id, @Description
    WHERE NOT EXISTS (SELECT NULL FROM table WHERE Id = @Id)

    COMMIT TRAN

注意:请解释否定答案

Before everyone jumps to HOLDLOCK-s out of fear from these nafarious users running your sprocs directly :-) let me point out that you have to guarantee uniqueness of new PK-s by design (identity keys, sequence generators in Oracle, unique indexes for external ID-s, queries covered by indexes). That's the alpha and omega of the issue. If you don't have that, no HOLDLOCK-s of the universe are going to save you and if you do have that then you don't need anything beyond UPDLOCK on the first select (or to use update first).

scproc通常在非常受控的条件下运行,并假设有可信的调用者(中间层)。这意味着如果一个简单的upsert模式(更新+插入或合并)看到重复的PK,这意味着在中间层或表设计中存在错误,SQL将在这种情况下调用错误并拒绝记录。在这种情况下,放置HOLDLOCK除了降低性能外,还等于吃掉异常并接收潜在的错误数据。

话虽如此,使用MERGE或UPDATE然后INSERT在您的服务器上更容易,而且更容易出错,因为您不必记得在第一次选择时添加(UPDLOCK)。此外,如果您正在小批量地进行插入/更新,则需要了解数据,以便决定某个事务是否合适。如果它只是一个不相关记录的集合,那么额外的“包络”交易将是有害的。

IF EXISTS (SELECT * FROM [Table] WHERE ID = rowID)
UPDATE [Table] SET propertyOne = propOne, property2 . . .
ELSE
INSERT INTO [Table] (propOne, propTwo . . .)

编辑:

唉,即使对我自己不利,我也必须承认,没有选择的解决方案似乎更好,因为它们少了一步就完成了任务。

做一个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')

如果你使用ADO。NET, DataAdapter处理这个。

如果你想自己处理,方法如下:

确保在键列上有一个主键约束。

然后你:

进行更新 如果更新失败是因为已经存在具有键的记录,则执行插入操作。如果更新没有失败,您就完成了。

你也可以反过来做,即先做插入,然后在插入失败时进行更新。通常第一种方法更好,因为更新比插入更频繁。