The following code demonstrates how to handle the various parameters and return a value from the dynamic SQL.
Rather than using a table-per-counter, the code uses a single table of counters with a name (CounterName
) assigned to each. Incrementing the different counters within the table is shown.
Instead of passing in a value to be incremented, e.g. the OP's @i
, the counters maintain their own values and the incremented value is returned on each execution. If passing in the value to be incremented is a requirement then the update
can be easily changed to use the value of @pCounter
as a source and the value can be passed in and returned using one parameter.
The table name is embedded in the update
statement and, as such, cannot be passed as a parameter. It must be inserted into the statement while it is being assembled. QuoteName
is used to handle problem names, e.g. Space Here
, and offer some protection against SQL injection.
The code can be tested at db<>fiddle. (At the time of this writing SQL Server 2019 appears to be non-functional at db<>fiddle. Hence the use of SQL Server 2017.)
-- Sample data.
-- The Counters table has a row for each counter to be kept, rather than a table per counter.
create table Counters ( CounterId Int Identity, Counter Int Default 0, CounterName NVarChar(64) );
insert into Counters ( CounterName ) values ( 'Shoes' ), ( 'Widgets' );
select * from Counters;
-- Build the query.
declare @Counter as Int = 0;
declare @SQL as NVarChar(500);
declare @ParameterDefinitions as NVarChar(100);
declare @TableName as SysName = N'Counters';
declare @CounterName as NVarChar(64) = 'Widgets';
-- Note that the table name needs to be substituted into the query here, not passed as a parameter.
-- Using different names for the parameters within the query and the variables being passed makes
-- things a little clearer.
set @SQL =
N'update ' + QuoteName( @TableName ) +
' set @pCounter = Counter += 1' +
' where CounterName = @pCounterName;';
set @ParameterDefinitions = N'@pCounterName NVarChar(64), @pCounter Int Output';
-- Execute the query.
-- Note that output parameters must be specified here as well as in the parameter definitions.
execute sp_ExecuteSQL @SQL, @ParameterDefinitions,
@pCounterName = @CounterName, @pCounter = @Counter output;
select @CounterName as [@CounterName], @Counter as [@Counter];
select * from Counters;
execute sp_ExecuteSQL @SQL, @ParameterDefinitions,
@pCounterName = @CounterName, @pCounter = @Counter output;
select @CounterName as [@CounterName], @Counter as [@Counter];
select * from Counters;
-- Try a different counter.
set @CounterName = N'Shoes';
execute sp_ExecuteSQL @SQL, @ParameterDefinitions,
@pCounterName = @CounterName, @pCounter = @Counter output;
select @CounterName as [@CounterName], @Counter as [@Counter];
select * from Counters;
-- Houseclean.
drop table Counters;