2016-05-15 3 views
0

У меня есть таблица под названием ReportValues, которая хранит всю информацию о игроке в парах ключей и значений В таблице есть внешний ключ из другой таблицы, называемой Reports. Я пытаюсь получить все данные в одной строке для каждого отчета, где ключи будут именами столбцов, а значения заполнят возвращенную таблицу. Если я вставляю @pID вручную, а не как параметр, то код работает, но при использовании параметра я получаю следующую ошибку: «Должен объявить скалярную переменную« @pID ». Вот мой код:Попытка передать параметры из asp.net при использовании инструкции DECLARE, но получить сообщение об ошибке «Должен объявить скалярную переменную» @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; 

} 
+0

Я не думаю, что вы можете передавать переменные в exec таким образом. Вы должны попробовать sp_executesql вместо –

+0

Эта проблема не имеет ничего общего с sp_executesql – Alex

ответ

1

«и RV2.value = @pID» является частью динамической строки и не рассматривается в качестве переменной в динамическом струна строительного запроса. В области видимости SQL Server распространяется только на исполняемый пакет или функцию, поэтому динамически созданный код, выполняемый внутри «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 +')

Другой (I будет лучше обсуждать):

"EXEC(@DynamicPIVOT) " 

с

"EXEC sp_executesql @DynamicPIVOT, N'@pID INT', @pID " 

Примечание: @DynamicPIVOT должен быть объявлен как NVARCHAR (MAX)
Примечание 2: объявить @pID быть тот же тип данных, как RV2.keyName. Это позволит избежать преобразований типов во время выполнения запроса.

Чтобы помочь в диагностировании подобных проблем в будущем, я предлагаю вам проверить значение sqlQuery непосредственно перед его выполнением и вставить его в студию управления SQL. Это позволит понять, какие части являются строками, а какие - исполняемым кодом SQL.

+0

Я пробовал это, но это не сработало. Вместо этого я создал хранимую процедуру, и она работает. Есть ли риск сделать это? – Orensig

+0

Если вы имеете в виду создание процедуры, то нет, никакого риска. – Alex

+0

Можете ли вы подробно остановиться на том, что не сработало для вас? – Alex

Смежные вопросы