使用动态 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();
我想更改参数化语句中的动态 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();