我想在参数化语句中更改动态SQL语句,但是在查询中表名称是动态的。因此,我尝试以这种方式来修饰整个语句,就像在this link中newCRMsupport的答案中看到的那样:
command.CommandType = CommandType.Text;
string sqlStr = " DECLARE @sqlSubstr nvarchar(max) SET @sqlSubstr = N'UPDATE quotename(@tempTable) = SET @flag = 1 WHERE @tempCol = @tempColVal' EXECUTE sp_executesql @sqlSubstr";
command.CommandText = sqlStr;
command.Parameters.AddWithValue("@tempTable", TemporaryTableName);
command.Parameters.AddWithValue("@flag", flagToUpdate);
command.Parameters.AddWithValue("@tempCol", ImportRegister.TemporaryTableKeyColumn);
command.Parameters.AddWithValue("@tempColVal", sourceRow[ImportRegister.TemporaryTableKeyColumn]);
command.ExecuteNonQuery();
但是当我运行它时,我有一个异常。 “必须声明calar变量@tempTable”,但我无法弄清缺少的内容。 谢谢
答案 0 :(得分:1)
像这样在数据库设计或应用程序设计上使用动态SQL都表明设计不佳。
但是,假设无法更改设计,那么当前SQL语句的问题在于您实际上并未使用动态SQL。
一个动态SQL看起来像这样:
DECLARE @sqlSubstr nvarchar(max) = N'UPDATE '+ quotename(@tempTable) +N'
SET '+ quotename(@flag) +N' = 1
WHERE '+ quotename(@tempCol) +' = @tempColVal;
EXECUTE sp_executesql @sqlSubstr, N'@tempColVal varchar(2)', @tempColVal;
请注意,表名和列名的参数被连接到代表您正在执行的SQL的字符串中。
另外,请注意,我还为列名添加了quotename
。
但是,我不确定这是否提供了针对SQL注入攻击的完全可靠的保护。 quotename
的使用确实提供了一些保护,但是我很确定可以克服这个问题。
为了真正保护自己,您必须将所有标识符列入白名单-因此,您首先需要查询information_schema.columns
以确保一切安全。
只有这样做,您才能确保代码是SQL Injection安全的。 在此期间,you really should stop using AddWithValue already.
这是您代码的修订版:
string sqlStr = @"DECLARE @sqlSubstr nvarchar(max) =
N'UPDATE '+ quotename(@tempTable) +
N' SET '+ quotename(@flag) +
N' = 1 WHERE '+ quotename(@tempCol) +' = @tempColVal'
IF EXISTS(
-- make sure both columns exists in the table
SELECT 1
FROM Information_schema.Columns
WHERE Table_Name = @tempTable
AND Column_Name IN(@flag, @tempCol)
HAVING COUNT(DISTINCT Column_Name) = 2
)
EXECUTE sp_executesql @sqlSubstr N'@tempColVal nvarchar' @tempColVal"; -- I had to guess the data type
command.CommandText = sqlStr;
command.Parameters.Add("@tempTable", SqlDbType.NVarChar).Value = TemporaryTableName;
command.Parameters.Add("@flag", SqlDbType.NVarChar).Value = flagToUpdate;
command.Parameters.Add("@tempCol", SqlDbType.NVarChar).Value = ImportRegister.TemporaryTableKeyColumn;
command.Parameters.Add("@tempColVal", SqlDbType.NVarChar).Value = sourceRow[ImportRegister.TemporaryTableKeyColumn]);
command.ExecuteNonQuery();