无法将值插入 SQL table,值被误认为是列
Trouble inserting values into SQL table, values get mistaken for columns
我不断收到异常:
"Invalid Column Name, 'IBM'."
错误发生在:"' + @ticker + '"
,即使在 VALUES
中声明了 @ticker
。我怀疑错误可能发生在查询的其他位置,但我对 SQL/T-SQL 还很陌生,所以我不确定如何找出位置。
private string InsertRecord(Indicator indicator)
{
try
{
if (!CheckIfColumnExists(indicator.GetType().Name))
{
AddColumn(indicator.GetType().Name, SqlDbType.Real);
}
const string query = @"
DECLARE @sql nvarchar(max) = '
INSERT INTO ' + QUOTENAME(@tableName) + '(
' + QUOTENAME(@indicator) + ', date, ticker)
VALUES(' + @indicatorValue + ', ' + @date + ', ' + @ticker + ')
';
EXEC sp_executesql @sql;
";
//checking if the record is already there
if (!CheckIfRecordExists(indicator))
{
using (SqlConnection conn = new SqlConnection(this.connectionstring))
{
conn.Open();
SqlCommand cmd = new SqlCommand(query , conn);
cmd.Parameters.AddWithValue("@tableName", tableName);
cmd.Parameters.AddWithValue("@indicator", indicator.GetType().Name);
cmd.Parameters.AddWithValue("@indicatorValue", indicator.Value.ToString());
cmd.Parameters.AddWithValue("@date", indicator.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@ticker", indicator.Ticker);
var result = cmd.ExecuteNonQuery();
return "New Record Inserted";
}
}
else
{
return "Record Already Exists";
}
}
catch
{
return "Failure Inserting New Record";
}
}
编辑:我接受 CharlieFace 的回答,因为它避免了通过 SQL 注入的违规行为,并解释了 sp_executesql.
的必要性
担忧
您不能使用参数附加 table 名称和列名称的值。相反,需要 字符串连接 ,尽管这将 导致开放的 SQL 注入攻击 (示例:Bobby Tables)。因此,请确保您已 对 tableName
或字符串连接部分进行了足够的验证。
您不需要为查询中的参数附加单引号 '
。当SQLCommand
根据参数类型追加SQLParameter
值进行查询时会自动完成。
我看不出有必要使用 EXEC sp_executesql
。虽然您可以 straight-way 执行 INSERT
查询。
在 Whosebug 社区中,通常会建议使用 SqlCommand.Add("@Name", SqlDbType).Value
并指定参数类型而不是 SqlCommand.AddWithValue()
。参考Can we stop using AddWithValue() already?.
总之,您的 SqlCommand
应该是:
string query = @"
INSERT INTO " + tableName +
"(" + indicator.GetType().Name + ", date, ticker)" +
" VALUES (@indicatorValue, @date, @ticker)";
SqlCommand cmd = new SqlCommand(query , conn);
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar).Value = indicator.Value.ToString();
cmd.Parameters.Add("@date", SqlDbType.NVarchar).Value = indicator.Date.ToString("yyyy-MM-dd");
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar).Value = indicator.Ticker;
您应该将包含数据(而不是列和 table 名称)的参数一直传递到 sp_executesql
const string query = @"
DECLARE @sql nvarchar(max) = '
INSERT INTO ' + QUOTENAME(@tableName) + '(
' + QUOTENAME(@indicator) + ', date, ticker)
VALUES(@indicatorValue, @date, @ticker)
';
EXEC sp_executesql @sql,
N'@indicatorValue nvarchar(100), @date date, @ticker nvarchar(100)',
@indicatorValue,
@date,
@ticker;
";
您还应该将参数作为它们的实际值(日期、整数)而不是 ToString
传递。同时显式声明参数类型和长度
// table and column name should be NVARCHAR(128)
cmd.Parameters.Add("@tableName", SqlDbType.NVarchar, 128).Value = tableName;
cmd.Parameters.Add("@indicator", SqlDbType.NVarchar, 128).Value = indicator.GetType().Name;
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar, 100).Value = indicator.Value;
cmd.Parameters.Add("@date", SqlDbType.Date).Value = indicator.Date;
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar, 100).Value = indicator.Ticker;
我不断收到异常:
"Invalid Column Name, 'IBM'."
错误发生在:"' + @ticker + '"
,即使在 VALUES
中声明了 @ticker
。我怀疑错误可能发生在查询的其他位置,但我对 SQL/T-SQL 还很陌生,所以我不确定如何找出位置。
private string InsertRecord(Indicator indicator)
{
try
{
if (!CheckIfColumnExists(indicator.GetType().Name))
{
AddColumn(indicator.GetType().Name, SqlDbType.Real);
}
const string query = @"
DECLARE @sql nvarchar(max) = '
INSERT INTO ' + QUOTENAME(@tableName) + '(
' + QUOTENAME(@indicator) + ', date, ticker)
VALUES(' + @indicatorValue + ', ' + @date + ', ' + @ticker + ')
';
EXEC sp_executesql @sql;
";
//checking if the record is already there
if (!CheckIfRecordExists(indicator))
{
using (SqlConnection conn = new SqlConnection(this.connectionstring))
{
conn.Open();
SqlCommand cmd = new SqlCommand(query , conn);
cmd.Parameters.AddWithValue("@tableName", tableName);
cmd.Parameters.AddWithValue("@indicator", indicator.GetType().Name);
cmd.Parameters.AddWithValue("@indicatorValue", indicator.Value.ToString());
cmd.Parameters.AddWithValue("@date", indicator.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@ticker", indicator.Ticker);
var result = cmd.ExecuteNonQuery();
return "New Record Inserted";
}
}
else
{
return "Record Already Exists";
}
}
catch
{
return "Failure Inserting New Record";
}
}
编辑:我接受 CharlieFace 的回答,因为它避免了通过 SQL 注入的违规行为,并解释了 sp_executesql.
的必要性担忧
您不能使用参数附加 table 名称和列名称的值。相反,需要 字符串连接 ,尽管这将 导致开放的 SQL 注入攻击 (示例:Bobby Tables)。因此,请确保您已 对
tableName
或字符串连接部分进行了足够的验证。您不需要为查询中的参数附加单引号
'
。当SQLCommand
根据参数类型追加SQLParameter
值进行查询时会自动完成。我看不出有必要使用
EXEC sp_executesql
。虽然您可以 straight-way 执行INSERT
查询。在 Whosebug 社区中,通常会建议使用
SqlCommand.Add("@Name", SqlDbType).Value
并指定参数类型而不是SqlCommand.AddWithValue()
。参考Can we stop using AddWithValue() already?.
总之,您的 SqlCommand
应该是:
string query = @"
INSERT INTO " + tableName +
"(" + indicator.GetType().Name + ", date, ticker)" +
" VALUES (@indicatorValue, @date, @ticker)";
SqlCommand cmd = new SqlCommand(query , conn);
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar).Value = indicator.Value.ToString();
cmd.Parameters.Add("@date", SqlDbType.NVarchar).Value = indicator.Date.ToString("yyyy-MM-dd");
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar).Value = indicator.Ticker;
您应该将包含数据(而不是列和 table 名称)的参数一直传递到 sp_executesql
const string query = @"
DECLARE @sql nvarchar(max) = '
INSERT INTO ' + QUOTENAME(@tableName) + '(
' + QUOTENAME(@indicator) + ', date, ticker)
VALUES(@indicatorValue, @date, @ticker)
';
EXEC sp_executesql @sql,
N'@indicatorValue nvarchar(100), @date date, @ticker nvarchar(100)',
@indicatorValue,
@date,
@ticker;
";
您还应该将参数作为它们的实际值(日期、整数)而不是 ToString
传递。同时显式声明参数类型和长度
// table and column name should be NVARCHAR(128)
cmd.Parameters.Add("@tableName", SqlDbType.NVarchar, 128).Value = tableName;
cmd.Parameters.Add("@indicator", SqlDbType.NVarchar, 128).Value = indicator.GetType().Name;
cmd.Parameters.Add("@indicatorValue", SqlDbType.NVarchar, 100).Value = indicator.Value;
cmd.Parameters.Add("@date", SqlDbType.Date).Value = indicator.Date;
cmd.Parameters.Add("@ticker", SqlDbType.NVarchar, 100).Value = indicator.Ticker;