patternsqlMinor
Run multiple stored procedures in sequence
Viewed 0 times
storedproceduressequencemultiplerun
Problem
I have a stored procedure written in T-SQL (SQL Server 2008 R2). It is a master procedure that essentially call multiple other subprocedures in sequence. The call and error handling is identical for each one except for the name of the procedure.
In an OO language I would use an abstraction such as an interface or functor and loop over a bunch of objects. That does not work in SQL, but I want to find some way to make this code more concise with less copy and paste repetition. Yes, I know that fundamentally SQL is about set operations and does not support what I want to do very well, but if there is a way, it will make the code much more concise. I also need to capture the result of each stored procedure invocation and do something with it which is not relevant to this question.
Here is what I have so far:
When I run the procedure, SQL Server gives me an error because the
I get a syntax error.
This works fine except for retrieving the return value of the subprocedures. Is there a way to accomplish my stated goal, and if so, how?
NOTE: based on what I asked here, a cursor would sound like a better implementation than a
In an OO language I would use an abstraction such as an interface or functor and loop over a bunch of objects. That does not work in SQL, but I want to find some way to make this code more concise with less copy and paste repetition. Yes, I know that fundamentally SQL is about set operations and does not support what I want to do very well, but if there is a way, it will make the code much more concise. I also need to capture the result of each stored procedure invocation and do something with it which is not relevant to this question.
Here is what I have so far:
CREATE PROCEDURE dbo.testproc
AS BEGIN
DECLARE @step INT, @result INT
DECLARE @tbl TABLE([step] INT, [pname] NVARCHAR(40))
INSERT INTO @tbl ([step], [pname]) VALUES (1, N'proc1')
INSERT INTO @tbl ([step], [pname]) VALUES (2, N'proc2')
INSERT INTO @tbl ([step], [pname]) VALUES (3, N'proc3')
-- Potentially many more procedures here
SET @step = 1
WHILE @step 0
BEGIN
INSERT INTO SomeTable error code and step number
RETURN
END
SET @step = @step + 1
END
END
GOWhen I run the procedure, SQL Server gives me an error because the
@result variable that is part of the dynamic SQL is not defined as part of the batch that is contained in the @sql variable. If I modify it like this:SET @sql = N'EXEC dbo.' + (SELECT [pname] FROM @tbl WHERE [step] = @step)
EXEC @result = (@sql)I get a syntax error.
This works fine except for retrieving the return value of the subprocedures. Is there a way to accomplish my stated goal, and if so, how?
NOTE: based on what I asked here, a cursor would sound like a better implementation than a
WHILE loop especially given the table variable. Part of the code that is not essenSolution
If you don't need the result values later you can do it shorter this way:
The variable engine will produce the following query batch
When the batch is executed it will stop executing when there is a @result not zero and keep that value in the output parameter.
More traditional looping
If you want to loop over the procedures. Since there are no parameters (or the parameters are all the same) you can simply call
-- procedures to test with
create proc proc1 as print '1' return 0
GO
create proc proc2 as print '2' return 1
GO
create proc proc3 as print '3' return 0
GO
if object_id('dbo.testproc') is null exec('create procedure dbo.testproc as return(0)')
GO
alter PROCEDURE dbo.testproc
AS
DECLARE @result INT
, @sql nvarchar(max) = N''
DECLARE @tbl TABLE([step] INT, [pname] nvarchar(513))
INSERT INTO @tbl ([step], [pname])
VALUES (1, N'proc1'),
(2, N'proc2'),
(3, N'proc3')
-- Potentially many more procedures here
select @sql = @sql + 'exec @result = ' + QUOTENAME(pname) + ' if @result <> 0 return;'
from @tbl order by step
exec sp_executesql @sql, N'@result int output', @result output
if @result <> 0
begin
print 'do your cleanup'
end
GO
exec testprocThe variable engine will produce the following query batch
exec @result = [proc1] if @result <> 0 return;
exec @result = [proc2] if @result <> 0 return;
exec @result = [proc3] if @result <> 0 return;When the batch is executed it will stop executing when there is a @result not zero and keep that value in the output parameter.
More traditional looping
If you want to loop over the procedures. Since there are no parameters (or the parameters are all the same) you can simply call
exec @result = @proc if object_id('dbo.testproc') is null exec('create procedure dbo.testproc as return(0)')
GO
alter PROCEDURE dbo.testproc
AS
DECLARE @result INT
, @proc sysname
DECLARE @tbl TABLE([step] INT, [pname] nvarchar(513))
INSERT INTO @tbl ([step], [pname])
VALUES (1, N'proc1'),
(2, N'proc2'),
(3, N'proc3')
-- Potentially many more procedures here
declare c cursor fast_forward local
for select pname from @tbl order by step
open c
fetch next from c into @proc
while @@FETCH_STATUS = 0
begin
exec @result = @proc
if @result <> 0
BREAK
fetch next from c into @proc
end
close c
deallocate c
if @result <> 0
begin
print 'do your cleanup'
end
GO
exec testprocCode Snippets
-- procedures to test with
create proc proc1 as print '1' return 0
GO
create proc proc2 as print '2' return 1
GO
create proc proc3 as print '3' return 0
GO
if object_id('dbo.testproc') is null exec('create procedure dbo.testproc as return(0)')
GO
alter PROCEDURE dbo.testproc
AS
DECLARE @result INT
, @sql nvarchar(max) = N''
DECLARE @tbl TABLE([step] INT, [pname] nvarchar(513))
INSERT INTO @tbl ([step], [pname])
VALUES (1, N'proc1'),
(2, N'proc2'),
(3, N'proc3')
-- Potentially many more procedures here
select @sql = @sql + 'exec @result = ' + QUOTENAME(pname) + ' if @result <> 0 return;'
from @tbl order by step
exec sp_executesql @sql, N'@result int output', @result output
if @result <> 0
begin
print 'do your cleanup'
end
GO
exec testprocexec @result = [proc1] if @result <> 0 return;
exec @result = [proc2] if @result <> 0 return;
exec @result = [proc3] if @result <> 0 return;if object_id('dbo.testproc') is null exec('create procedure dbo.testproc as return(0)')
GO
alter PROCEDURE dbo.testproc
AS
DECLARE @result INT
, @proc sysname
DECLARE @tbl TABLE([step] INT, [pname] nvarchar(513))
INSERT INTO @tbl ([step], [pname])
VALUES (1, N'proc1'),
(2, N'proc2'),
(3, N'proc3')
-- Potentially many more procedures here
declare c cursor fast_forward local
for select pname from @tbl order by step
open c
fetch next from c into @proc
while @@FETCH_STATUS = 0
begin
exec @result = @proc
if @result <> 0
BREAK
fetch next from c into @proc
end
close c
deallocate c
if @result <> 0
begin
print 'do your cleanup'
end
GO
exec testprocContext
StackExchange Database Administrators Q#80184, answer score: 5
Revisions (0)
No revisions yet.