Sql server 使用sp_executesql使用自动增量更新表
我试图将这个简单的sql语句转换为sp_executesql,因为表名是可变的:Sql server 使用sp_executesql使用自动增量更新表,sql-server,tsql,dynamic-sql,Sql Server,Tsql,Dynamic Sql,我试图将这个简单的sql语句转换为sp_executesql,因为表名是可变的: UPDATE @TableName SET @i = RowNumber = @i + 1 这就是我想到的,但它在执行时给出了一个错误:必须声明表变量@TableName DECLARE @i AS INT ; SET @i = 0 ; DECLARE @SQLString NVARCHAR(500); DECLARE @ParmDefinition NVARCHAR(500); SET @SQLString
UPDATE @TableName SET @i = RowNumber = @i + 1
这就是我想到的,但它在执行时给出了一个错误:必须声明表变量@TableName
DECLARE @i AS INT ;
SET @i = 0 ;
DECLARE @SQLString NVARCHAR(500);
DECLARE @ParmDefinition NVARCHAR(500);
SET @SQLString = N'UPDATE @TableName SET @i = RowNumber = @i + 1';
SET @ParmDefinition = N'@TableName VARCHAR(30), @i TINYINT';
EXECUTE sp_executesql @SQLString, @ParmDefinition, @TableName=@TableName, @i = @i;
我正在尝试向现有表中添加另一列,这基本上类似于ID递增的标识列。表已经有一个ID列,我无法删除/更新它
请不要推荐标识栏
我在一个存储过程中执行这个查询,@TableName作为一个参数进入,并且是一个临时表的名称,所以我希望它在所有内部作用域中都可用,包括sp_exec。当您将变量放在引号中时,它不会被计算,只是文本。 另外,最好显式写入要更新的列名
DECLARE @i AS INT ;
SET @i = 0 ;
DECLARE @ColumnName as NVARCHAR(1000) ='MyColumn'
DECLARE @TableName as NVARCHAR(1000) = 'MyTable'
DECLARE @SQLString NVARCHAR(500);
SET @SQLString = N'UPDATE ' + @TableName + ' SET ' + @ColumnName + ' = ' + @i + '+1';
EXECUTE sp_executesql @SQLString;
结论-您应该在单个变量中连接整个更新字符串,然后通过sp_executesql运行它。首先,表名不能参数化。我建议改为使用QUOTENAME作为字符串文本进行保护。如果同时提供了schema和tablename,则必须将它们作为单独的参数提供并引用 第二:SET@i=RowNumber=@i+1'看起来是一种使用连续整数迭代更改RowNumber的方法。为此,我将使用带有行号的updatetable cte,并在此处添加起始位置@I 第三:假设表中已经存在列RowNumber。如果不是动态的,则必须首先发出ALTERTABLE ADD RowNumber INT 完整代码:
DECLARE @TableName SYSNAME = 't';
DECLARE @i AS INT = 0 ;
DECLARE @SQLString NVARCHAR(MAX);
DECLARE @ParmDefinition NVARCHAR(MAX);
SET @SQLString =
N'WITH cte AS (SELECT *, rn = ROW_NUMBER() OVER(ORDER BY (SELECT 1)) FROM <TableName>)
UPDATE cte SET RowNumber = @i + rn';
SET @ParmDefinition = N'@i TINYINT';
SET @SQLString = REPLACE(@SQLString, '<TableName>', QUOTENAME(@TableName));
PRINT @SQLString; -- debug
EXECUTE sp_executesql @SQLString, @ParmDefinition, @i = @i;
使用CONCAT函数而不是+运算符
更新表列
通过使用嵌套子查询,可以更新表的列
SET @SQL=CONCAT('UPDATE X',' SET X.',@Col_NAME,' = X.ID FROM (SELECT ',@Col_NAME,', ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as ID FROM ',QUOTENAME(@TABLE_NAME),' ) X')
SELECT @SQL
EXEC (@SQL)
下面的代码演示如何处理各种参数并从动态SQL返回值 代码不使用每个计数器的表,而是使用一个计数器表,并为每个计数器分配名称CounterName。将显示递增表中不同计数器的值 计数器不传递要递增的值,例如OP的@i,而是维护自己的值,每次执行时返回递增的值。如果需要传入要递增的值,那么可以很容易地更改更新以使用@pCounter的值作为源,并且可以使用一个参数传入并返回该值 表名嵌入在update语句中,因此不能作为参数传递。在汇编语句时,必须将其插入语句中。QuoteName用于处理问题名称,例如此处的空格,并提供一些针对SQL注入的保护 代码可以在以下位置进行测试。在撰写本文时,SQLServer2019在DBFIDLE上似乎不起作用。因此使用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;
您使用的是哪种数据库管理系统?这段代码非常特定于产品。好吧,它是的半个副本,并且没有将@i声明为输出。旁白:缺少where子句,更新将应用于所有行。如果有多行,您希望返回哪个行号?您可能还想看看。这也不是运行动态语句的方式。您需要使用QUOTENAME安全地注入该值。如果您可以像这样参数化一个表名,您根本不需要动态SQL。@jarlh我正在使用SQL Server 2016
-- 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;