SQL Server 2005实现MySQL替换成INTO?


86

MySQL具有非常有用但专有的REPLACE INTOSQL命令。

可以在SQL Server 2005中轻松模拟吗?

开始一个新的事务,先执行aSelect()然后再执行UPDATEor或INSERTandCOMMIT总是很麻烦,尤其是在应用程序中执行该操作时,因此始终保留该语句的2个版本。

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

Answers:


60

这让我很讨厌MSSQL(我的博客上的rant)。我希望MSSQL受支持upsert

@ Dillie-O的代码在较旧的SQL版本(+1票)中是个好方法,但它仍然基本上是两个IO操作(theexists然后theupdateinsert)。

基本上,这篇文章有一个更好的方法:

--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 Sql2008merge从SQL:2003标准引入:

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操作,但是代码很糟糕:-(


十分感谢!保存Select,并且在我可以确定在Update和“ my”插入之间没有该键的其他插入的情况下,通常甚至不需要做任何事情。
Michael Stum

2
@Michael如果您要使用此解决方案,则最好在此表上具有唯一索引,并处理重复的键错误。
山姆·萨弗隆

3
@Keith您的merge语句不起作用。MERGE不支持该WHERE子句,则必须使用USING和重写该子句ON。另外,除非添加,否则会发生WITH (HOLDLOCK)争用,并且INSERT可能会发生并发,其中之一由于键冲突而失败。
Evgeniy Berezovsky

是的,如此处指出:weblogs.sqlteam.com/dang/archive/2009/01/31/…合并不是原子的。它取出一个隐式更新锁,但在执行插入操作之前将其释放,这会导致竞争条件,从而导致主键冲突。除隐式UPDLOCK之外,还必须使用显式HOLDLOCK,以使操作成为原子操作。就目前而言,尽管看起来只是一个陈述,但它不是原子的。
Triynko 2013年

1
MERGE语法是错误的,并且在同一位作者的更新答案中得到修复:stackoverflow.com/a/243670/24472
Larry

21

您正在寻找的功能通常称为UPSERT。Atleast知道它的名字可能会帮助您找到所需的内容。

我认为SQL Server 2005没有任何出色的方法可以做到这一点。2008年引入了MERGE语句,可用于完成此操作,如下所示:http : //www.databasejournal.com/features/mssql/article.php/3739131http://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server-2008-MERGE.aspx

Merge在2005年的Beta中可用,但在最终版本中将其删除。


18

upsert / merge正在做的事情对...的影响

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

因此,希望这些文章和此伪代码的结合可以使事情前进。


10

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

底线是,如果您希望廉价的更新并希望并发使用是安全的,请尝试:

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个插入操作。因此,如果您通常进行更新,那么这是一种安全且便宜的选择。

我还要非常小心,不要使用任何对并发使用都不安全的方法。产生主键冲突或在生产中重复行真的很容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.