我正在使用MS SQL Server Management Studio 2012中的存储过程。
我正在重用其他过程中的一些代码,这包括使用EXEC
命令调用另一个存储过程。
此过程将把对象的信息作为参数,重置该对象的状态,然后查找相关(下游)对象并重置其状态。
代码正在运行,但即使它没有处于错误状态,也需要对重置和相关对象的状态进行一些小改动。为了解决这个问题,我在主循环之前创建了一个迭代相关对象的变量,然后当遇到具有错误状态的第一个对象时,它设置变量的值。变量本身是BIT
。
以下是程序:
USE [DB_TEST]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[resetTasksInErrorStatus]
@TaskId INT,
@SubjectId INT,
@ProjectProtocolId INT,
@TimePointId INT,
@WorkbookId INT,
@LogCreatorUserId INT,
@LogReasonTypeId INT,
@LogOtherReason VARCHAR(256),
@SignatureCaptured BIT,
@ManualChangeTaskStatus BIT,
@ErrorIfModifiedAfter DATETIME,
@NewTaskStatusID INT,
@ProcessorUserId INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION ResetTasksInError
-- Make sure the task has not been modified since the reset was requested
IF(EXISTS(
SELECT ti.* FROM TaskInstance as ti
WHERE ti.ModifyDate > @ErrorIfModifiedAfter
AND ti.TaskId = @TaskId
AND ti.SubjectId = @SubjectId
AND ti.ProjectProtocolId = @ProjectProtocolId
AND ti.TimePointId = @TimePointId
AND ti.WorkbookId = @WorkbookId))
BEGIN
RAISERROR('The task to be reset was modified before the reset could complete', 16, 1);
GOTO error
END
-- Get all downstream task instances
SELECT *
INTO #downstreamTaskInstances
from dbo.fnGetTaskInstancesDownstream
(
@TaskId,
@SubjectId,
@TimePointId
)
-- Get the previous task status
DECLARE @OldTaskStatus INT;
SELECT TOP 1 @OldTaskStatus = ti.TaskStatusTypeId FROM TaskInstance as ti
WHERE ti.TaskId = @TaskId
AND ti.SubjectId = @SubjectId
AND ti.TimePointId = @TimePointId
-- Reset the task
EXEC setTaskStatus
@TaskID,
@SubjectId,
@ProjectProtocolId,
@TimePointId,
@WorkBookId,
@OldTaskStatus,
@NewTaskStatusID,
@ProcessorUserId,
@LogCreatorUserId,
@LogReasonTypeId,
@LogOtherReason,
@SignatureCaptured,
@ManualChangeTaskStatus,
NULL,
NULL,
NULL,
1
-- Check if setTaskStatus rolled back our transaction
IF(@@TRANCOUNT = 0)
BEGIN
RAISERROR('Error in sub procedure. Changes rolled back.', 16, 1);
RETURN
END
-- Set a boolean variable to determine whether downstream tasks should be reset
DECLARE @ResetDownstreamTasks BIT = 0;
--Set @ResetDownstreamTasks = 0;
-- Create a cursor of the downstream tasks
DECLARE downstreamCursor CURSOR FOR
SELECT TaskId, TimePointId, ProcessorUserId, TaskStatus, WorkBookId, ProjectProtocolId, IsManual, TaskStatus
FROM #downstreamTaskInstances
OPEN downstreamCursor
-- Reset each downstream task to unprocessed
DECLARE @CursorTaskID INT;
DECLARE @CursorTimePointID INT;
DECLARE @CursorProcessorUserId INT;
DECLARE @CursorTaskStatusID INT;
DECLARE @CursorWorkBookId INT;
DECLARE @CursorProjectProtocolId INT;
DECLARE @CursorIsManual BIT;
Declare @CursorTaskStatus INT;
FETCH NEXT FROM downstreamCursor INTO @CursorTaskID, @CursorTimePointId, @CursorProcessorUserId, @CursorTaskStatusID, @CursorWorkBookId, @CursorProjectProtocolId, @CursorIsManual, @CursorTaskStatus
WHILE @@FETCH_STATUS = 0 AND @@ERROR = 0 AND @@TRANCOUNT = 1
BEGIN
-- Check if the task is in error status, and then make sure it is not an manual task.
-- Manual tasks should never be in error status, so there is no need to reset them.
if @CursorTaskStatus = 10 and @CursorIsManual <> 1
begin
SET @ResetDownstreamTasks = 1;
EXEC setTaskStatus
@CursorTaskID,
@SubjectId,
@CursorProjectProtocolId,
@CursorTimePointId,
@CursorWorkBookId,
@CursorTaskStatusID,
1, -- Unprocessed
@CursorProcessorUserId,
@LogCreatorUserId,
@LogReasonTypeId,
@LogOtherReason,
@SignatureCaptured,
@ManualChangeTaskStatus,
NULL,
NULL,
NULL,
0
end;
if @ResetDownstreamTasks = 1
begin
EXEC setTaskStatus
@CursorTaskID,
@SubjectId,
@CursorProjectProtocolId,
@CursorTimePointId,
@CursorWorkBookId,
@CursorTaskStatusID,
6, -- Inspected
@CursorProcessorUserId,
@LogCreatorUserId,
@LogReasonTypeId,
@LogOtherReason,
@SignatureCaptured,
@ManualChangeTaskStatus,
NULL,
NULL,
NULL,
0
end
FETCH NEXT FROM downstreamCursor INTO @CursorTaskID, @CursorTimePointId, @CursorProcessorUserId, @CursorTaskStatusID, @CursorWorkBookId, @CursorProjectProtocolId, @CursorIsManual, @CursorTaskStatus
END
DROP TABLE #downstreamTaskInstances
CLOSE downstreamCursor
DEALLOCATE downstreamCursor
-- Check if setTaskStatus rolled back our transaction
IF(@@TRANCOUNT = 0)
BEGIN
RAISERROR('Error in sub procedure. Changes rolled back.', 16, 1);
RETURN
END
IF(@@ERROR <> 0)
BEGIN
GOTO ERROR
END
COMMIT TRANSACTION ResetTasksInError
RETURN
ERROR:
RAISERROR('Error encountered. Changes rolled back.', 16,1);
ROLLBACK TRANSACTION ResetTasksInError
RETURN
END
当我运行该程序时,我得到了这些错误:
Msg 266, Level 16, State 2, Procedure setTaskStatus, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
Msg 16943, Level 16, State 4, Procedure resetTasksInErrorStatus, Line 197
Could not complete cursor operation because the table schema changed after the cursor was declared.
Msg 3701, Level 11, State 5, Procedure resetTasksInErrorStatus, Line 200
Cannot drop the table '#downstreamTaskInstances', because it does not exist or you do not have permission.
Msg 50000, Level 16, State 1, Procedure resetTasksInErrorStatus, Line 207
Error in sub procedure. Changes rolled back.
如果我注释掉SET ...
语句,则该过程运行并且有效(不符合要求)。
我四处寻找类似的问题,但没有一个能解决我的问题。
关于SET语句,我有什么遗漏吗?
它是否以某种方式影响@@TRANCOUNT
变量?
我确实看到一些帖子提到问题很可能是在这个调用的存储过程中,但是我有点犹豫,因为存储过程有效,并且这些错误只在尝试设置值时出现变量。
答案 0 :(得分:1)
只是一个猜测..但我认为会发生以下情况:
所以你应该检查一个内部sps中的错误。
希望它有所帮助。
答案 1 :(得分:0)
我找到了一种使存储过程正常工作的方法。
我所做的是从if语句中删除了存储过程EXEC
语句,该语句设置了变量的值。
所以循环中的代码如下所示:
WHILE @@FETCH_STATUS = 0 AND @@ERROR = 0 AND @@TRANCOUNT = 1
BEGIN
-- Check if the task is in error status, and then make sure it is not an manual task.
-- Manual tasks should never be in error status, so there is no need to reset them.
if @CursorTaskStatus = 10 and @CursorIsManual <> 1
begin
SET @ResetDownstreamTasks = 1;
end;
if @ResetDownstreamTasks = 1
begin
EXEC setTaskStatus
@CursorTaskID,
@SubjectId,
@CursorProjectProtocolId,
@CursorTimePointId,
@CursorWorkBookId,
@CursorTaskStatusID,
6, -- Inspected
@CursorProcessorUserId,
@LogCreatorUserId,
@LogReasonTypeId,
@LogOtherReason,
@SignatureCaptured,
@ManualChangeTaskStatus,
NULL,
NULL,
NULL,
0
end
FETCH NEXT FROM downstreamCursor INTO @CursorTaskID, @CursorTimePointId, @CursorProcessorUserId, @CursorTaskStatusID, @CursorWorkBookId, @CursorProjectProtocolId, @CursorIsManual, @CursorTaskStatus
END