我在T-SQL中编写了一些异常/错误处理。
目标是继续插入操作,即使其中一个插入导致错误。
当前代码如下所示:
INSERT INTO targettable
SELECT
*, GETDATE()
FROM
table_log l
LEFT JOIN
someothertable m ON l.id = m.id
WHERE
l.actiontype = 'insert'
问题:有时,表table_log
中存在错误的行/条目。这会导致整个插入操作回滚。我希望服务器在发生错误后继续执行插入操作。
我的想法:我可以使用游标单独处理每个插入。但据我所知,这在性能方面会很糟糕。我还可以使用ignore_dup_key
或XACT_ABORT OFF
。但我强烈怀疑我们的DBA会允许这样做。另外,我也不认为这也是一个很好的解决方案。
这是另一个想法:
DECLARE @rowcount int
SET @rowcount = (SELECT COUNT(*) FROM table_log l WHERE actiontype = 'insert')
BEGIN TRY
WHILE @rowcount > 0
BEGIN
looppoint:
INSERT INTO target_table
SELECT somecolumn, GETDATE()
FROM table_log l
LEFT JOIN some_other_table m
ON l.id = m.id
WHERE l.actiontype = 'insert' AND
l.id NOT IN
(SELECT id
FROM noinsert_table)
SET @rowcount = @rowcount -1
END
END TRY
BEGIN CATCH
execute sp_some_error_catching_procedure
INSERT INTO noinsert_table
SELECT SCOPE_IDENTITY()
SET @rowcount = @rowcount -1
GOTO looppoint
END CATCH
基本上,我想捕获导致错误的行并使用此信息在下一个循环中从插入中排除行。但是我不确定这是否会奏效,我不认为SCOPE_IDENTITY
会给我一个失败行的ID,只有成功的行。此外,这似乎过于复杂,容易出现其他问题。
如果有人有提示,我很乐意听到。
答案 0 :(得分:1)
为什么不在插入数据之前或作为插入选择的一部分清理数据?这样,您只是尝试插入您知道将适合您要插入的表的参数的数据。然后你仍然可以使用基于集合的插入。
顺便说一下,请永远不要写那样的代码。您应始终始终在语句的插入部分和select中指定插入中的列,并且永远不要使用select *
。如果有人重新排列表中的列,您的插入将中断或更糟,不会中断但将数据放入错误的列中。如果有人在插入到选定表中时不需要添加列,则插入将中断。这种事情是一个SQL反模式。