[英]SQL Server Try Catch
我有一個存儲過程,該存儲過程由SQL代理每x分鍾運行一次。 該存儲過程具有一個while循環,該循環讀取每一行並對它們執行某些操作。
我想處理while循環中發生的錯誤。 我需要在CATCH
塊中使用Throw
,因為這樣SQL Server代理將不會通知是否發生錯誤。
但是問題是,如果我使用throw塊,它將打破while循環,但不處理其他記錄。
如何在while循環中使用TRY CATCH
,如果發生錯誤,應繼續while循環?
這是我的代碼:
WHILE @i<@Count OR @Count IS NULL
BEGIN
SELECT @Id = NULL --Clear variable
SELECT TOP 1
@Id = Id,
@TableNo = [TableNo],
@Action = [Action],
@RecId = [RecId],
@NDB = dbo.GetDB(CId)
FROM
dbo.alot WITH (NOLOCK)
WHERE
CId = @Cid
AND Error = 0
AND (@Table IS NULL OR TableNo = @Table)
AND Tableno <> 50109
ORDER BY
Id
IF @Id IS NOT NULL
BEGIN
SELECT
@SQL = N'EXECUTE @RC = ['+dbo.GetDB(@CId)+'].[dbo].[alot_web] @TableNo, @Action, @RecId, @NaviDB'
BEGIN TRY
IF @RecId = '0-761345-27353-4'
BEGIN
SELECT 1 / 0; -- Generate an error here.
END
EXEC master.dbo.sp_executesql @SQL, N'@TableNo nvarchar(12), @Action tinyint, @RecId nvarchar(36), @NDB varchar(12), @RC int OUTPUT'
, @TableNo, @Action, @RecId, @NaviDB, @Rc OUTPUT
END TRY
BEGIN CATCH
DECLARE @Description VARCHAR(1024);
SELECT @Description = 'WebQueue ID: ' + ISNULL(CAST(@Id AS VARCHAR), '') + ' CompanyID: ' + ISNULL(@Cid, '') + ' Action: ' + ISNULL(CAST(@Action AS VARCHAR), '') + ' RecID: ' + ISNULL(CAST(@RecId AS VARCHAR), '') + ' @RC: ' + ISNULL(CAST(@RC AS VARCHAR), '');
EXEC dbo.LogError @Description;
THROW;
END CATCH
IF @RC = 0 AND @@ERROR = 0
BEGIN
IF EXISTS(SELECT * FROM Queue
WHERE CId = @CId AND [Action] = @Action
AND TableNo = @Tableno AND RecId = @RecID AND Id <> @Id)
BEGIN
DELETE FROM Queue
WHERE CId = @CId AND [Action] = @Action AND TableNo = @Tableno
AND RecId = @RecID
SELECT @Ok += @@ROWCOUNT
END
ELSE BEGIN
DELETE FROM Queue WHERE Id = @Id
SELECT @Ok += @@ROWCOUNT
END
END
ELSE BEGIN
IF EXISTS(SELECT * FROM Queue
WHERE CId = @CId AND [Action] = @Action
AND TableNo = @Tableno AND RecId = @RecID AND Id <> @Id)
BEGIN
UPDATE Queue
SET Error = 1
WHERE CId = @CId AND [Action] = @Action AND TableNo = @Tableno AND RecId = @RecID
SELECT @Failed += @@ROWCOUNT
END
ELSE BEGIN
UPDATE Queue
SET Error = 1
WHERE Id = @Id
SELECT @Failed += @@ROWCOUNT
END
END
END
ELSE
BREAK
SELECT @i += 1
/*IF @i>0 BEGIN--logging >>
INSERT INTO [AdminDB].[dbo].[Replication_Log] ([Date],[CId],[Loops],[DurationSS],[Ok],[Failed])
SELECT Getdate(),@CId,@i,DATEDIFF(ss,@Startdt,getdate()),@Ok,@Failed
END */
END
您的THROW
引發了一個異常,該異常導致SP停止處理。 本質上,您正在捕獲發生的任何錯誤,但是將它們重新拋出,這確實會打破while
循環。 刪除它,然后sp應該照常繼續。
我的建議是在循環之外再使用一個循環。 因此,TSQL將是這樣,這會有所幫助嗎?
DECLARE @Continue bit,
@i INT,
@Count INT
SELECT @i = 1 ,
@Count =10
SET @Continue =1
While @Continue=1
BEGIN
BEGIN TRY
--YOUR existing while loop
WHILE @i<@Count OR @Count IS NULL
BEGIN
-- The rest of your code
IF @i=3
BEGIN
set @i= @i/0
END
PRINT @i
SET @i=@i+1
--Set to false when complete
IF @i =@Count
SET @Continue =0
END
END TRY
BEGIN CATCH
print ERROR_MESSAGE()
set @i =@i+1
END CATCH
END
以上預期結果
1
2
Divide by zero error encountered.
4
5
6
7
8
9
TRY / CATCH不能捕獲所有錯誤。 在這種情況下,sp_start_job實際上會調用外部過程,而這些過程超出了SQL Server錯誤處理的范圍。 或至少這就是他們堅持的故事:
http://connect.microsoft.com/SQLServer/feedback/details/362112/sp-start-job-error-handling
請參閱此以獲取更多詳細信息
用CONTINUE替換THROW; 這樣,將在不取消代碼的情況下處理下一條記錄。
(編輯!)
因為您記錄錯誤
EXEC dbo.LogError @Description;
我認為您不需要重新拋出錯誤。 既然您說過,您不希望程序結束。
繼續的示例:
DECLARE @intFlag INT
SET @intFlag = 1
WHILE (@intFlag <=5)
BEGIN
PRINT @intFlag
SET @intFlag = @intFlag + 1
CONTINUE;
IF @intFlag = 4 -- This will never executed
BREAK;
END
GO
來源: http : //blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/
編輯:
為您的工作中介:
在過程頂部創建一個新變量:
int @ErrorAmount = 0
您的漁獲量需要如下所示:
BEGIN CATCH
DECLARE @Description VARCHAR(1024);
SELECT @Description = 'WebQueue ID: ' + ISNULL(CAST(@Id AS VARCHAR), '') + ' CompanyID: ' + ISNULL(@Cid, '') + ' Action: ' + ISNULL(CAST(@Action AS VARCHAR), '') + ' RecID: ' + ISNULL(CAST(@RecId AS VARCHAR), '') + ' @RC: ' + ISNULL(CAST(@RC AS VARCHAR), '');
EXEC dbo.LogError @Description;
SET @ErrorAmount = @ErrorAmount+1; --add this line
CONTINUE; --REPLACE THROW with CONTINUE
END CATCH
在您的過程結束時添加
if @ErrorAmount > 0
BEGIN
THROW 6000,'Your message' , 1;
END
這樣,您的代理將向您顯示錯誤,並且您的整個過程仍然可以完成任務。
你可以:
THROW
。 您的腳本將繼續正常運行,並且將記錄錯誤 @Failed
並在適當的情況下使用RAISEERROR
,SQL Agent會指出該錯誤
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.