Sometimes you may need to create an sql agent job, which process sql commands inside a FIFO queue (which is implemented by an user table which an auto identity integer), and if one command raises error, log the error into an error log table, then continue the next command. Such job can be implemented by using a LOCAL FAST_FORWARD CURSOR, TRY...CATCH statement, and TRANSACTION statements. Below is an example illustrating how to do it.
-- Create Tables
CREATE TABLE QueueCommands (
ID bigint IDENTITY(1,1) NOT NULL PRIMARY KEY,
SqlCommand varchar(500) NOT NULL
)
GO
CREATE TABLE CompletedCommands (
ID bigint NOT NULL,
SqlCommand varchar(500) NOT NULL
)
GO
-- Error Log Table
CREATE TABLE ErrorLog(
errorTime datetime NOT NULL CONSTRAINT DF_ErrorLog_errorTime DEFAULT (getdate()),
errorMsg nvarchar(2048) NULL
)
GO
-- Error Logger Stored Procedure
CREATE OR ALTER PROC error_handler_sp AS
BEGIN
DECLARE @errmsg nvarchar(2048),
@severity tinyint,
@state tinyint,
@errno int,
@proc sysname,
@lineno int
SELECT @errmsg = error_message(), @severity = error_severity(),
@state = error_state(), @errno = error_number(),
@proc = error_procedure(), @lineno = error_line()
IF @errmsg NOT LIKE '***%'
BEGIN
SELECT @errmsg = '*** ' + coalesce(quotename(@proc), '<dynamic SQL>') +
', Line ' + ltrim(str(@lineno)) + '. Errno ' +
ltrim(str(@errno)) + ': ' + @errmsg
END
INSERT ErrorLog (errorMsg) VALUES (@errmsg);
RAISERROR('%s', @severity, @state, @errmsg)
END
GO
-- Create the Stored Procedure to be called by sql agent job
CREATE OR ALTER PROC JobProcessCommands
AS
BEGIN
SET XACT_ABORT ON;
SET NOCOUNT ON;
CREATE TABLE #tmpQueueCommands (
ID bigint PRIMARY KEY,
SqlCommand varchar(500)
);
INSERT #tmpQueueCommands (ID, SqlCommand) SELECT ID, SqlCommand FROM QueueCommands;
DECLARE @cur_ID bigint, @cur_SqlCommand varchar(500);
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT ID, SqlCommand FROM #tmpQueueCommands ORDER BY ID
OPEN cur
WHILE 1 = 1
BEGIN
FETCH cur INTO @cur_ID, @cur_SqlCommand
IF @@FETCH_STATUS <> 0 BREAK
BEGIN TRY
BEGIN TRAN
EXECUTE(@cur_SqlCommand);
IF @@ERROR = 0
BEGIN
DELETE TOP(1) QueueCommands OUTPUT deleted.* INTO CompletedCommands WHERE ID = @cur_ID;
END
COMMIT
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK
EXEC error_handler_sp
END CATCH
END
CLOSE cur
DEALLOCATE cur
DROP TABLE #tmpQueueCommands;
END
GO
-- Example
INSERT QueueCommands VALUES ('SELECT 1');
INSERT QueueCommands VALUES ('SELECT 1/0'); -- Error
INSERT QueueCommands VALUES ('SELECT 2');
SELECT * FROM QueueCommands
EXEC JobProcessCommands
SELECT * FROM QueueCommands
SELECT * FROM CompletedCommands
SELECT * FROM ErrorLog