如何忽略T-SQL中的"重复键"错误(SQL Server)

Kin*_*oon 50 sql sql-server

我有一个包含多个SQL语句(INSERT,UPDATE和/或DELETES)的事务.执行时,我想忽略重复错误语句并继续下一个语句.这样做的最佳方法是什么?

Emm*_*uel 64

我认为您正在寻找索引上的IGNORE_DUP_KEY选项.请查看http://msdn.microsoft.com/en-us/library/ms186869.aspx中记录的IGNORE_DUP_KEY ON选项,该选项会导致重复插入尝试产生警告而不是错误.

  • @Jonathan Leffler:`IGNORE_DUP_KEY`不会导致重复数据.它导致SQL Server忽略重复键:不将其插入数据库. (39认同)
  • @Jonathan Leffler:错误理解这个功能不是你的错.这是非常可靠的记录:"*如果您创建一个唯一索引,您可以设置此选项以确保索引列中的每个值都是唯一的.*".多年来,我认为选项是插入时引发的错误或调用COMMIT时延迟的错误.原来这不是那些.最好将其命名为"忽略,跳过,不要插入,重复行" (8认同)
  • 不好的想法 - 您不希望在唯一索引中重复数据. (3认同)
  • @Ian Boyd 和 Canoehead 谢谢,确实它没有很好的记录,很多人甚至不知道它的存在,更不用说它是如何工作的了:) (2认同)
  • A具有多对多关系,产品和类别.我有一个只有product_id和category_id的表以及一个唯一索引.使用IGNORE_DUP_KEY,我可以将产品(a,b,c)添加到categoies(x,y,x),而不必担心某些产品是否已经属于其中一个类别.我只关心最终的结果. (2认同)
  • @LeifNeland - 我同意。太多人很快就认为这是一个坏主意*在所有情况下*。总是有一些合法的情况,跳过重复的插入并不是不明智的。需要超过评论字符数限制才能清楚解释的案例... (2认同)

Phi*_*ley 19

扩展您对SquareCog回复的评论,您可以:

INSERT INTO X VALUES(Y,Z)    WHERE Y  NOT IN (SELECT Y FROM X)
INSERT INTO X2 VALUES(Y2,Z2) WHERE Y2 NOT IN (SELECT Y FROM X2)
INSERT INTO X3 VALUES(Y3,Z3) WHERE Y3 NOT IN (SELECT Y FROM X3)
Run Code Online (Sandbox Code Playgroud)

在这里,我假设列Y存在于所有三个表中.请注意,如果表未在Y上编制索引,则性能会很差.

哦,是的,Y对它有一个独特的约束 - 所以它们被索引,这应该是最佳的.

  • 我喜欢这个 - 我们的部署脚本设计为安全运行多次,因此INSERT总是有标准来避免冲突. (2认同)
  • 我尝试了这种方法,但我的MSSQL Server(2008 R2)comaplains关于"关键字'WHERE'附近的语法不正确" - 它似乎不喜欢INSERT后面的WHERE.你确定你的解决方案是正确的吗? (2认同)
  • @Dai我在使用SQL Azure时遇到了同样的问题.我不确定这是否是SQL Azure的限制.这就是我最终使用的内容:INSERT into test(col1,col2)SELECT DISTINCT 1,'a'FROM测试WHERE NOT EXISTS(SELECT col1 FROM test WHERE col1 = 1) (2认同)

zin*_*lon 15

虽然我强烈建议你构建你的sql以便不尝试重复插入(Philip Kelley的代码片段可能是你需要的),但我想提一下语句上的错误并不一定会导致回滚.

除非XACT_ABORTON,否则如果遇到错误,事务将不会自动回滚,除非它严重到足以终止连接.XACT_ABORT默认为OFF.

例如,以下sql成功地在表中插入三个值:

create table x ( y int not null primary key )

begin transaction
insert into x(y)
values(1)
insert into x(y)
values(2)
insert into x(y)
values(2)
insert into x(y)
values(3)
commit
Run Code Online (Sandbox Code Playgroud)

除非您正在设置XACT_ABORT,否则会在客户端上引发错误并导致回滚.如果由于某种可怕的原因你无法避免插入重复项,你应该能够在客户端上捕获错误并忽略它.


use*_*593 10

如果通过"Ignore Duplicate Error statments",中止当前语句并继续执行下一个语句而不中止trnsaction,那么只需在每个语句周围放置BEGIN TRY .. END TRY:

BEGIN TRY
    INSERT ...
END TRY
BEGIN CATCH /*required, but you dont have to do anything */ END CATCH
...
Run Code Online (Sandbox Code Playgroud)


Vin*_*rgh 8

我想要了解以下内容:

如果99%的数据在没有错误的情况下插入而事先做出选择会导致巨大的性能下降(例如,在我的情况下,从200行/秒到20行/秒),而"哑"插入和偶尔捕获错误.

忽略了"违反PRIMARY KEY约束"错误后,事情又回到了其他资源的瓶颈状态(净空被定义为"瓶颈资源没有的东西").

这就是我首先参与讨论的全部原因.