Sql Server 2005 - 插入如果不存在

问题描述:

互联网上有很多关于这个常见“问题”的信息。Sql Server 2005 - 插入如果不存在

解决方案,如:

IF NOT EXISTS() BEGIN INSERT INTO (...) END 

不是线程安全的在我看来,你可能会同意。

但是,您是否可以确认将存在放入单个select的where子句中可以解决sql引擎中并发性最高的问题? 够了吗?

insert into Table (columns) 
select column1, column2, column3 
where not exists (select top 1 1 from Table where something) 

应该在那里也加入了一些更高的事务级或 可以这样在一个默认的执行:承诺?

这项工作在未提交的水平下?

谢谢!

//后来添加

我可以假设两个SQL”是正确的:

1) 组事务隔离级别重复的读取

IF NOT EXISTS() BEGIN INSERT INTO (...) END 

2)事务隔离级别设置重复读

insert into Table (columns) 
select column1, column2, column3 
where not exists (select top 1 1 from Table where something) 
+1

没有也不会在任READCOMMITTED或工作未提交的级别。您需要一些额外的锁定提示。 [只有插入一行,如果它不在那里](http:// *。com/questions/3407857 /只插入一行 - 如果它不是已经存在的) – 2011-05-25 07:24:25

+1

你不需要“帮忙”存在子句 - 它们足够聪明,可以在他们看完之后完成1排。你可以执行'EXISTS(SELECT * FROM ...'并且它做的是正确的事情。 – 2011-05-25 07:26:14

+0

它会做正确的事情,但是对于cocurrency而言它不是线程安全的,并且在高的情况下可能会发生主要违规错误因此根据@Martin的链接,应该添加可重复的读取隔离事务 – Paul 2011-05-25 07:35:57

使用TRY/CAT CH就可避免额外读

BEGIN TRY 
    INSERT etc 
END TRY 
BEGIN CATCH 
    IF ERROR_NUMBER() <> 2627 
     RAISERROR etc 
END CATCH 
  • 一个NOT EXISTS将读取表,插入无论是在IF或WHERE
  • 需要读来检查的独特性

如果可以的话丢弃重复,这是一种高度可扩展的技术

链接:

+0

好吧,但如果我应该插入或更新然后:我可以这样做:如果error_number()= 2627开始更新...结束? – Paul 2011-05-25 07:52:13

+0

@Paul:查看我的最后一个链接,然后处理UPDATE – gbn 2011-05-25 07:53:59

+0

是否有可能在启动catch块时引发默认错误?或者我必须爆炸获取error_number和消息来满足raiserror参数? – Paul 2011-05-25 09:28:08

要回答这个问题,更新将repeatable read仍然是不够的。

这是您需要的holdlock/serializable级别。

你正试图阻止phantoms(其中第一阅读没有行符合标准,因此NOT EXISTS返回true,但随后并发事务插入一行满足它)

+0

看来,我会开始在编写sql语句时偏执狂:) – Paul 2011-05-25 08:09:52

+0

@Paul - 'serializable'也会给你造成死锁的风险,这可以通过'UPDLOCK,HOLDLOCK'来避免。尽管我自己会使用'TRY ... CATCH'。 – 2011-05-25 08:18:57