使用动态 table 名称查询

Query with dynamic table name

我想更改参数化语句中的动态 SQL 语句,但在查询中 table 名称是动态的。所以我尝试以这种方式对整个语句进行参数化,正如我在 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();

但是当我 运行 它时,我有一个异常。 "Must declare calar variable @tempTable",我不知道我错过了什么。 谢谢

像这样使用动态 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;

请注意 table 名称和列名称的参数连接到表示您正在执行的 SQL 的字符串中。
另外,请注意我也在列名中添加了 quotename

但是,我不确定这是否提供了针对 SQL 注入攻击的 full-proof 保护。 quotename 的使用确实提供了一些保护,但我很确定可以克服这个问题。
要真正保护自己,您必须 white-list 所有标识符 - 因此您首先需要查询 information_schema.columns 以确保一切安全。

只有这样做,您才能确定代码是 SQL 注入安全的。 当我们这样做的时候,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();