MySQL的SQL Server 2005实现REPLACE INTO?

MySQL具有这种令人难以置信的有用而又适当的 REPLACE INTO SQL命令。

这可以很容易地在SQL Server 2005中模拟吗?

开始一个新的事务,执行 Select(),然后执行 UPDATEINSERTCOMMIT 有点痛苦,特别是在应用程序中执行它时,因此始终保留2个版本的声明。

我想知道是否有一种简单且通用的方法在SQL Server 2005中实现这样的功能?

0
额外 编辑
意见: 1

4 答案

upsert / merge正在做什么是...的作用...

IF EXISTS (SELECT * FROM [Table] WHERE Id = X)
   UPDATE [Table] SET...
ELSE
   INSERT INTO [Table]

所以希望这些文章和这个伪代码的结合可以让事情发生变化。

0
额外

您寻找的功能传统上称为UPSERT。至少知道它叫什么可能会帮助你找到你要找的东西。

I don't think SQL Server 2005 has any great ways of doing this. 2008 introduces the MERGE statement that can be used to accomplish this as shown in: http://www.databasejournal.com/features/mssql/article.php/3739131 or http://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx

Merge在2005年的测试版中可用,但他们在最终版本中删除了它。

0
额外

我撰写了有关此问题的博客文章

最重要的是,如果你想要便宜的更新......并且你想要保证并发使用。尝试:

update t
set hitCount = hitCount + 1
where pk = @id

if @@rowcount < 1 
begin 
   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
end

通过这种方式,您可以对更新进行1次操作,对于插入操作最多可进行3次操作。所以,如果你通常更新这是一个安全便宜的选择。

我也非常小心,不要使用任何不安全的并发使用。在生产中获取主键违规或重复行很容易。

0
额外

这让我对MSSQL感到恼火(在我的博客上咆哮)。我希望MSSQL支持 upsert

@ Dillie-O的代码是旧版SQL版本(+1投票)的好方法,但它仍然基本上是两个IO操作( exists ,然后是 update代码>插入</代码>)

这篇文章中有一个稍微好一点的方法,基本上是:

--try an update
update tablename 
set field1 = 'new value',
    field2 = 'different value',
    ...
where idfield = 7

--insert if failed
if @@rowcount = 0 and @@error = 0
    insert into tablename 
           ( idfield, field1, field2, ... )
    values ( 7, 'value one', 'another value', ... )

如果是更新,则将其减少为一个IO操作,如果是插入,则减少两个。

MS Sql2008从SQL:2003标准引入 merge

merge tablename as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

现在它只是一个IO操作,但代码非常糟糕:-(

0
额外
万分感谢!保存选择,并且通常甚至不需要电子交易,在我可以确定更新和“我的”插入之间的情况下,该键没有其他插入。
额外 作者 Michael Stum,
@Michael如果你打算使用这个解决方案,你最好在这个表上有一个唯一的索引,并处理重复的键错误。
额外 作者 Sam Saffron,
是的,正如这里指出的那样: weblogs.sqlteam.com/dang/archive/2009/01/31/… MERGE不是原子的。它取出隐式更新锁,但在执行插入操作之前将其释放,这会导致竞争条件导致主键违例。除了隐式UPDLOCK外,您还必须使用显式的HOLDLOCK,以使操作成为原子操作。就目前而言,尽管看起来只是一个单一的陈述,但它并不是原子的。
额外 作者 Triynko,
@Keith你的合并声明不起作用。 MERGE 不支持 WHERE 子句,您必须使用 USINGON 重写。此外,除非添加 WITH(HOLDLOCK),否则会出现竞争,并发可能会发生,其中一个由于键冲突而失败。
额外 作者 Eugene Beresovsky,
MERGE语法错误,它在来自同一作者的更新近的答案中得到解决: stackoverflow.com/a/243670/24472</一>
额外 作者 Larry,
上面的插入,然后进行更新仍然可能失败。使用唯一的密钥,您可以在插入中获得重复的密钥例外。我建议添加到您的更新声明:UPDATE表WITH(SERIALIZABLE)SET ...
额外 作者 Elan,