Это моя хранимая процедура, которая вызывается каждые две минуты заданием SQL.
USE [MyDB]
GO
/****** Object: StoredProcedure [dbo].[usp_Process_Invoice_USPs] Script Date: 27/03/2019 11:39:01 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ==================================================
-- Author: Mych
-- Create date: 20/03/2019
-- Description: This stored procedure will create
-- an in-memory table and get any uncompleted rows
-- from the Queue table. For each row found it
-- will construct an Exec statement and execute it.
-- it then marks the row as completed.
-- =================================================
ALTER PROCEDURE [dbo].[usp_Process_Invoice_USPs]
AS
DECLARE @QueueID INT,
@ProcName NVARCHAR(100),
@Username NVARCHAR(50),
@UserEmail NVARCHAR(100),
@ParamName NVARCHAR(50),
@ParamValue INT,
@QueuedOn Datetime,
@ParamOut NVarchar(200),
@RowCnt INT,
@MaxRows INT,
@ExecSql NVARCHAR(Max),
@ResultfromUSP NVARCHAR(250),
@Return NVARCHAR(250)
SELECT @RowCnt = 1
-- Create an in-memory table - Doing this as this is the only way I can think of to guarantee that rownum will be consecutive
-- the ID column in Tbl_Invoicing_Queue is an Identity column but numbers can be missed out when an insert fails for some reason.
DECLARE @Import TABLE (rownum INT IDENTITY (1, 1) PRIMARY KEY NOT NULL , QueueID INT NOT NULL, ProcName NVARCHAR(100),
Username NVARCHAR(50), UserEmail NVARCHAR(100), ParamName NVARCHAR(50), ParamValue int, QueuedOn datetime)
-- Insert any uncompleted rows (Progress = 'Queued') from the Queue to the in-memory table
INSERT INTO @Import (QueueID, ProcName, Username, UserEmail, ParamName, ParamValue, QueuedOn)
SELECT ID, ProcName, Username, UserEmail, ParamName, ParamValue, QueuedOn FROM TBL_Invoicing_Queue WHERE Progress = 'Queued'
-- Find out how many rows were imported.
SELECT @MaxRows=count(*) FROM @Import
--loop through each row... get the field values and construct a sql Exec statement based on the values
--Execute the Exec Statement
--Write all details and result to the completed table... Progress will be either completed or failed dependant of @ResultfromUSP
--Delete the row from the queued table.
while @RowCnt <= @MaxRows
begin
SELECT @QueueID = QueueID FROM @Import WHERE rownum = @RowCnt;
SELECT @ProcName = ProcName FROM @Import WHERE rownum = @RowCnt;
SELECT @UserName = UserName FROM @Import WHERE rownum = @RowCnt;
SELECT @UserEmail = UserEmail FROM @Import WHERE rownum = @RowCnt;
SELECT @ParamName = ParamName FROM @Import WHERE rownum = @RowCnt;
SELECT @ParamValue = ParamValue FROM @Import WHERE rownum = @RowCnt;
SELECT @QueuedOn = QueuedOn FROM @Import WHERE rownum = @RowCnt
Update TBL_Invoicing_Queue SET Progress = 'In Progress - ' + CONVERT(VARCHAR, FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss', 'en-GB')) Where ID = @QueueID
SET @ExecSql = N'EXEC dbo.' + @ProcName
If @ParamName <> ''
BEGIN
SET @ParamOut = N'@User = ''' + @UserName + ''', @EmailAddress = ''' + @UserEmail + ''', @' + @ParamName + ' = ' + CAST(@ParamValue AS NVARCHAR(20))
END
ELSE
BEGIN
SET @ParamOut = N'@User = ''' + @UserName + ''', @EmailAddress = ''' + @UserEmail + ''', @Return = @Return out'
END
--Execute our exec statement and get returned result (string) which will either be SUCCESS or a message detailing a failure.
EXEC sp_executesql @ExecSql, @ParamOut, @ResultfromUSP = @Return out
--dependant on Result we insert the following into the completed table
SELECT @ResultfromUSP
PRINT @ResultfromUSP
PRINT 'Got result back from USP'
IF @ResultfromUSP = 'SUCCESS'
BEGIN
Insert INTO TBL_Invoicing_Completed (QID, ProcName, Username, UserEmail, ParamName, ParamValue, QueuedOn, Progress, Result) Values
(@QueueID, @ProcName, @UserName, @UserEmail, @ParamName, @ParamValue, @QueuedOn, 'Completed - ' + CONVERT(VARCHAR, FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss', 'en-GB')), @ResultfromUSP)
END
ELSE
BEGIN
Insert INTO TBL_Invoicing_Completed (QID, ProcName, Username, UserEmail, ParamName, ParamValue, QueuedOn, Progress, Result) Values
(@QueueID, @ProcName, @UserName, @UserEmail, @ParamName, @ParamValue, @QueuedOn, 'FAILED - ' + CONVERT(VARCHAR, FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss', 'en-GB')), @ResultfromUSP)
END
-- remove the row from the queued table
DELETE FROM TBL_Invoicing_Queue Where ID = @QueueID
-- increment the count and loop to next row
Select @RowCnt = @RowCnt + 1
end
-- NO need to drop @Import as this is cleared automatically
Все различные USP выставления счетов, которые будет выполнять этот USP, имеют выходной параметр @Return.Возврат по счету USP либо УСПЕХ, либо ОШИБКА ... Подробная информация об ошибке Это было проверено и работает, как и ожидалось.
Проблема заключается в том, что вышеупомянутый USP, который динамически вызывает Invoicing USP, не получает вывод @Return.Я подозреваю, что моя проблема с:
EXEC sp_executesql @ExecSql, @ParamOut, @ResultfromUSP = @Return out
Я даже пытался ...
EXEC sp_executesql @ExecSql, @ParamOut, @ResultfromUSP out
, но я не могу понять, почему.
Любойпомощь оценена.
ОБНОВЛЕНИЕ Спасибо за все ваши комментарии ... Этот usp запускается SqlJob каждые 2 минуты.Поэтому, как правило, есть только одна работа, которую нужно обрабатывать, иногда их может быть две.Таблица очередей имеет первичный ключ в ProcName, поэтому пользователи не могут запускать одну и ту же процедуру, пока не завершится процедура в очереди.Если они пытаются, они возвращают сообщение, информирующее их о том, что задание, использующее эту Процедуру, поставлено в очередь или находится в процессе выполнения, а также дает имя пользователя, который запросил это задание.
Мне пришлось реализовать этот поток рабочей очереди какНекоторые из запрашиваемых процедур сами могут занять от 20 до 30 минут.Выполнение их непосредственно со стороны клиента означало, что время ожидания страницы может истечь.
Вышеописанная процедура работает абсолютно нормально, за исключением того, что я не получаю возврата от EXEC sp_executesql….и поэтому следующий бит кода всегда вставляет поставленную в очередь запись в завершенную таблицу со статусом FAILED, даже если это на самом деле УСПЕХ.
Я справился с этим, имея инструкцию switch, основанную на @ParamNameвыполняет жестко запрограммированный EXEC usp_xxxxx вместо динамического построения SQL и использования EXEC sp_executesql….