在使用 DECLARE 语句时尝试从 asp.net 传递参数,但收到错误提示 "Must declare the scalar variable "@pID”
Trying to pass parameters from asp.net when using a DECLARE statement but getting an error saying "Must declare the scalar variable "@pID"
我有一个名为 ReportValues 的 table,它以键值对的形式存储有关玩家的所有信息。 table 有一个来自另一个名为 Reports 的 table 的外键。我试图为每个报告获取一行中的所有数据,其中键将是列名,值将填充返回的 table。如果我手动插入 @pID 而不是作为参数,那么代码可以工作,但是当使用参数时我会收到以下错误:"Must declare the scalar variable "@pID”。这是我的代码:
public DataTable getBarChartData(int p_ID)
{
//this query is transposing rows into columns as each key gets a column and the grouping variable is RV.report
string sqlQuery = "DECLARE @keyName AS VARCHAR(MAX) ";
sqlQuery += "SELECT @keyName = ";
sqlQuery += "COALESCE(@keyName + ', ', '') + CAST(keyName AS VARCHAR(20)) ";
sqlQuery += "FROM(SELECT DISTINCT keyname FROM ReportValues) ActivePlayers ";
sqlQuery += "SELECT @keyName keyNames ";
sqlQuery += "DECLARE @DynamicPIVOT AS VARCHAR(MAX) ";
sqlQuery += "SELECT @DynamicPIVOT = 'SELECT ' + @keyName + ";
sqlQuery += "' FROM ( ";
sqlQuery += "SELECT RV.report, RV.keyname, RV.value FROM ReportValues RV ";
sqlQuery += "join ReportValues RV1 on RV.report = RV1.report ";
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = @pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
sqlQuery += "WHERE r.timeStamp >= dateadd(hour, -240, GETDATE()) ";
sqlQuery += ") ";
sqlQuery += ") ActivePlayers";
sqlQuery += "PIVOT(";
sqlQuery += "MAX(value) FOR keyname IN(' + @keyName + ') ";
sqlQuery += ") Result; ' ";
sqlQuery += "EXEC(@DynamicPIVOT) ";
int pID = p_ID;
//this passes the query and param to an execution function
DataTable dtLabels = GetBarChartDataByUser(sqlQuery, pID);
return dtLabels;
}
//this is the sql execution function
public DataTable GetBarChartDataByUser(string strQuery, int pID)
{
SqlConnection con = new SqlConnection(createConnectionReadOnly());
con.Open();
try
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = strQuery;
cmd.Parameters.AddWithValue("@pID", pID);
SqlDataAdapter dap = new SqlDataAdapter(cmd);
//here is where I get the error
DataSet ds = new DataSet();
dap.Fill(ds);
return ds.Tables[0];
}
catch (Exception ex)
{
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
return null;
}
"and RV2.value = @pID" 是动态字符串的一部分,不会被视为动态字符串构建查询中的变量。在 SQL 中,服务器变量范围仅扩展到当前正在执行的批处理或函数,因此在 "EXEC()" 中执行的动态构建代码不知道变量 @pID。
您可以通过几种方式解决问题,其中之一如下:
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = @pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
到
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = ' + CONVERT( VARCHAR, @pID ) + ' and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
(注意'+ @pID +')
另一个(我认为更好的方法)是替换:
"EXEC(@DynamicPIVOT) "
和
"EXEC sp_executesql @DynamicPIVOT, N'@pID INT', @pID "
注意: @DynamicPIVOT 必须声明为 NVARCHAR( MAX )
注2: 将@pID 声明为与RV2.keyName 相同的数据类型。这将避免在查询执行期间进行类型转换
为了帮助将来诊断类似问题,我建议您在执行 sqlQuery 之前检查它的值并将其粘贴到 SQL Management studio 中。
这将清楚哪些部分是字符串,哪些部分是 SQL 可执行代码。
我有一个名为 ReportValues 的 table,它以键值对的形式存储有关玩家的所有信息。 table 有一个来自另一个名为 Reports 的 table 的外键。我试图为每个报告获取一行中的所有数据,其中键将是列名,值将填充返回的 table。如果我手动插入 @pID 而不是作为参数,那么代码可以工作,但是当使用参数时我会收到以下错误:"Must declare the scalar variable "@pID”。这是我的代码:
public DataTable getBarChartData(int p_ID)
{
//this query is transposing rows into columns as each key gets a column and the grouping variable is RV.report
string sqlQuery = "DECLARE @keyName AS VARCHAR(MAX) ";
sqlQuery += "SELECT @keyName = ";
sqlQuery += "COALESCE(@keyName + ', ', '') + CAST(keyName AS VARCHAR(20)) ";
sqlQuery += "FROM(SELECT DISTINCT keyname FROM ReportValues) ActivePlayers ";
sqlQuery += "SELECT @keyName keyNames ";
sqlQuery += "DECLARE @DynamicPIVOT AS VARCHAR(MAX) ";
sqlQuery += "SELECT @DynamicPIVOT = 'SELECT ' + @keyName + ";
sqlQuery += "' FROM ( ";
sqlQuery += "SELECT RV.report, RV.keyname, RV.value FROM ReportValues RV ";
sqlQuery += "join ReportValues RV1 on RV.report = RV1.report ";
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = @pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
sqlQuery += "WHERE r.timeStamp >= dateadd(hour, -240, GETDATE()) ";
sqlQuery += ") ";
sqlQuery += ") ActivePlayers";
sqlQuery += "PIVOT(";
sqlQuery += "MAX(value) FOR keyname IN(' + @keyName + ') ";
sqlQuery += ") Result; ' ";
sqlQuery += "EXEC(@DynamicPIVOT) ";
int pID = p_ID;
//this passes the query and param to an execution function
DataTable dtLabels = GetBarChartDataByUser(sqlQuery, pID);
return dtLabels;
}
//this is the sql execution function
public DataTable GetBarChartDataByUser(string strQuery, int pID)
{
SqlConnection con = new SqlConnection(createConnectionReadOnly());
con.Open();
try
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = strQuery;
cmd.Parameters.AddWithValue("@pID", pID);
SqlDataAdapter dap = new SqlDataAdapter(cmd);
//here is where I get the error
DataSet ds = new DataSet();
dap.Fill(ds);
return ds.Tables[0];
}
catch (Exception ex)
{
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
return null;
}
"and RV2.value = @pID" 是动态字符串的一部分,不会被视为动态字符串构建查询中的变量。在 SQL 中,服务器变量范围仅扩展到当前正在执行的批处理或函数,因此在 "EXEC()" 中执行的动态构建代码不知道变量 @pID。
您可以通过几种方式解决问题,其中之一如下:
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = @pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
到
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = ' + CONVERT( VARCHAR, @pID ) + ' and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
(注意'+ @pID +')
另一个(我认为更好的方法)是替换:
"EXEC(@DynamicPIVOT) "
和
"EXEC sp_executesql @DynamicPIVOT, N'@pID INT', @pID "
注意: @DynamicPIVOT 必须声明为 NVARCHAR( MAX )
注2: 将@pID 声明为与RV2.keyName 相同的数据类型。这将避免在查询执行期间进行类型转换
为了帮助将来诊断类似问题,我建议您在执行 sqlQuery 之前检查它的值并将其粘贴到 SQL Management studio 中。 这将清楚哪些部分是字符串,哪些部分是 SQL 可执行代码。