我已经写了一个存储过程,将做一个更新的记录的存在,否则它将会插入。它看起来像这样的东西:

update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)

我的逻辑背后写入它以这种方式是,将更新执行一个隐含的选择使用其中的条款,如果返回0然后插入会发生。

替代做这种方式将要做一个选择,然后可以基于数量返回的行要么更新或插入。这个我认为是低效率的,因为如果你是来做一个更新,它将导致选择2(第一次明确选择和第二隐含在其中的更新)。如果该进程要做插入然后会有任何差别的效率。

是我的逻辑的声音在这里?这是你将如何结合一个插入和更新存储proc?

有帮助吗?

解决方案

你的假设是正确的,这是最佳方式做到这一点,这就是所谓 更新插入/合并.

重要的更新插入,从sqlservercentral.com:

对于每一个更新的情况下上面提到的我们是去掉一个 另外从表读,如果我们 使用更新插入,而不是存在的。不幸的是插入, 更新插入,如果存在着方法的使用 同样数量的读。因此,检查存在 只应当有一个 非常有效的理由来证明的 另外I/O.优化的方式 做的事情,是确保你 有点读取尽可能在 DB。

最好的策略是要尝试的 更新。如果没有行影响 更新后插入。在大多数 的情况下,该行已经 存在与只有一个I/O将 需要。

编辑:请看看 这个答案 和链接的博客了解有关问题与这种模式和如何使其工作的安全。

其他提示

请阅读 后在我的博客 对于一个良好的、安全的模式,可以使用。有很多的考虑因素,并且接受的回答关于这个问题远远不是安全的。

对于一个快速回答试试下面的图案。它将工作现在SQL2000年以上。SQL2005给了你错误的处理,它打开了其他的选择和SQL2008给你一个合并的命令。

begin tran
   update t with (serializable)
   set hitCount = hitCount + 1
   where pk = @id
   if @@rowcount = 0
   begin
      insert t (pk, hitCount)
      values (@id,1)
   end
commit tran

如果要使用与SQL服务器2000/2005的原始代码需要被包围的交易,以确保数据保持一致,在并发的情况。

BEGIN TRANSACTION Upsert
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
COMMIT TRANSACTION Upsert

这将产生额外业绩成本,但是将确保数据的完整性。

添加,如已经建议,合并应用。

合并是一种新的特点在SQL服务器2008年,通过方式。

你不仅需要运行它在交易中,它还需要高隔离水平。我实际上默认的隔离级别读了致力于和这个代码需要序列化。

SET transaction isolation level SERIALIZABLE
BEGIN TRANSACTION Upsert
UPDATE myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
  begin
    INSERT into myTable (ID, Col1, Col2) values (@ID @col1, @col2)
  end
COMMIT TRANSACTION Upsert

也许也加入了@@error检查和回退可能是个好主意。

如果你不做一个合并在SQL2008你必须改变它:

如果@@rowcount=0@@error=0

否则,如果更新由于某些原因失败后,它将试图一插入之后,因为rowcount上的一个失败的声明是0

大风扇更新插入的,真的削减了代码管理。这里是另一种办法,我这样做:输入参数之一是ID,如果ID is NULL或0,你知道这是一个插入,否则它的更新。假设应用知道如果有一个ID,因此不会在所有情况下工作,但将削减的执行的一半,如果你这样做。

你的逻辑似乎是合理的,但是你可能想要考虑添加一些代码,以防止插入如果你已经通过在一个特定的主要关键。

否则,如果你总是在做一个插入如果更新不影响任何记录、时会发生什么某人删除的记录在你面前"更新插入"运行?现在记录你试图更新并不存在,因此,它将创建一个记录。这可能不是该行为。

修改后的移民及多文化事务部马伦科员额:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

BEGIN TRANSACTION UPSERT 

UPDATE MYTABLE 
SET    COL1 = @col1, 
       COL2 = @col2 
WHERE  ID = @ID 

IF @@rowcount = 0 
  BEGIN 
      INSERT INTO MYTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

IF @@Error > 0 
  BEGIN 
      INSERT INTO MYERRORTABLE 
                  (ID, 
                   COL1, 
                   COL2) 
      VALUES      (@ID, 
                   @col1, 
                   @col2) 
  END 

COMMIT TRANSACTION UPSERT 

你可以捕获的错误和送记录的失败插入表格。
我需要这样做,因为我们正在采取的任何数据是通过发送户如果可能固定它的内部。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top