我正在对一个存储过程进行故障排除,该存储过程应该将数据从一个SQL Server示例发送到Azure上托管的另一个SQL Server示例。
存储过程在研究它之后的工作方式是,它首先根据参数计算出它要传输哪些表,所以我最后得到一个表变量@transferTable
,如下所示
id tableName
===================
23 tableName1
55 tableName23
72 tableName111
在一个循环中,外观设置为
SELECT @recordID = MIN(id) FROM @transferTable
WHILE @recordID IS NOT NULL
BEGIN
-- Update attempt
UPDATE transferlog
SET LastAttempt = GetDate()
WHERE id = @recordID;
-- attempt
SET @SQLCommand 'Insert into Azure.dbo.table blah blah' -- this part is broken right now
print 'about to run sql command' --this prints
Execute (@SQL Command)
print 'ran sql' --this does not print
-- Update success
UPDATE transferlog
SET LastUpdate = GetDate()
WHERE id=@recordID;
SELECT @recordID = MIN(id) FROM @transferTable WHERE id > @recordID
END
这是这个存储过程如何工作的草图。现在它在第一个表上失败了,我知道原因-Azure版本的表上有一个NOT NULL约束,它试图插入的一个记录中有一个NULL值。这对我来说是有意义的。
没有意义的是,传输日志表不仅更新了列中包含有问题的NULL值的第一个表的LastAttempt
和LastUpdate
列,而且还更新了其后所有表的LastAttempt
和LastUpdate
列。
为什么会发生这种情况?虽然存储过程的作者预期LastUpdate
会在且仅在未发生错误的情况下运行,但似乎并非如此。如何确保LastUpdated列实际上仅在插入Azure SQL Server数据库时未发生错误的情况下更新?
1条答案
按热度按时间qvtsj1bj1#
SQL Server中的错误并不都是“相同的”,有些错误不会导致批处理中止,延迟批处理中的错误,通过使用
EXEC (@SQL)
或(更好的)sys.sp_executesql
,不会导致外部批处理结束(这实际上也是经常需要的行为),更不用说还有一些“批处理前”中止,因为它们发生在批处理被解析的时候。取以下批次:
这仍将导致返回包含
2
和3
的结果集,尽管这两个语句都在延迟批处理错误中执行。实际上,如果我们将这些语句移出延迟批处理,那么您 * 仍然 * 得到
1
和2
:但是请注意,
3
不会返回,因为引用一个不存在的对象会导致同一范围内的批处理中止错误。如果您想确保批处理总是被中止,那么一个方法是启用
XACT_ABORT
:这只会导致返回
1
,您可能还需要确保您的BEGIN
和COMMIT
是TRANSACTION
,以便在出现故障时“自动”回滚任何内容。或者,您可以使用
BEGIN TRY... CATCH
,但是,我并没有真正看到它的好处: