动态SQL更新命令

时间:2017-07-03 14:59:04

标签: sql sql-server dynamic

我正在使用MSSQL 2016,

我需要能够动态更新表上的行。

我有一个存储过程:

CREATE PROCEDURE sp_lookupData_UpdatelookupValues
 (
 @FullTableName nvarchar(50), 
 @Id nvarchar(10),
 @Name nvarchar(50),
 @Description nvarchar(50)
 )
AS
BEGIN

DECLARE @Cmd nvarchar(150) = N'UPDATE ' + @FullTableName + ' SET Name = ' +  @Name  + ', Description = ' + @Description + ' WHERE ID = ' + @Id + '';

EXECUTE sp_executesql @Cmd;

END

问题是Name和Description值会像这样传递到@Cmd:

UPDATE TABLE_NAME SET Name = Private, Description = Default WHERE ID = 1

而不是私人'和'默认'。

结果是一个错误,其中Private被计为不存在的列(因为格式错误)。

Invalid column name 'Private'.

3 个答案:

答案 0 :(得分:4)

自己加上引号

PrivateDefault周围使用单引号 而且由于您使用的是动态查询,因此您必须将单引号加倍才能逃脱它们。

DECLARE @Cmd nvarchar(150) = N'UPDATE ' + @FullTableName + ' SET Name = ''' +  @Name  + ''', Description = ''' + @Description + ''' WHERE ID = ' + @Id + '';

另外请确保您尝试下一个解决方案,因为第一个解决方案是SQL注入兼容的。

使用sp_executesql参数

您也可以使用@Cmd内的参数而不自行进行连接,但将参数传递给sp_executesql

另外,如果表格名称中有空格,我建议您QUOTENAME @FullTableName参数。

DECLARE @Cmd nvarchar(150) = N'UPDATE QUOTENAME(@FullTableName) SET Name = @Name, Description = @Description WHERE ID = @Id;'
EXEC sp_executesql @Cmd, @FullTableName, @Name, @Description, @Id;

这样做的好处是,您可以避免应用程序未检查的任何参数能够执行SQL注入。

参考:

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql

答案 1 :(得分:0)

您必须自己添加引号。我更喜欢使用QUOTENAME来保持所有引号可识别:

QUOTENAME(@FullTableName, '''')

答案 2 :(得分:0)

您不能将参数用于标识符。但是,您可以使用值的参数:

DECLARE @Cmd nvarchar(150) = N'
UPDATE ' + @FullTableName + '
    SET Name = @Name,
        Description = @Description 
WHERE ID = @Id';

EXECUTE sp_executesql @Cmd,
        N'@Name nvarchar(50), @Description nvarchar(50), @Id nvarchar(10)',
        @Name = @Name, @Description = @Description, @Id = @id;

不幸的是,动态表名称在SQL注入和语法错误方面仍然存在风险。我猜这是"控制"代码,而不是用户输入的代码,因此风险可能是可以接受的。但是,您可能应该使用quotename()

这引出了另一个问题,这可能是问题的症结所在。为什么有多个具有相同列的表?这些 - 应该这些 - 都可以存储在一个表中吗?这种类型的代码会质疑数据模型的各个方面。