SqlCommand возвращает ошибку при попытке выполнить запрос с помощью С#

Я работаю над проектом, который позволит пользователям создавать запросы, просто выбирая столбцы.

Мое приложение работает нормально и генерирует правильные запросы. Но когда я выполняю запрос, я получаю следующее исключение

Столбец Tasks.Duration недопустим в списке выбора, поскольку он не содержится ни в агрегатной функции, ни в предложении GROUP BY.

Что не делает, так это то, что мой запрос на самом деле включает правильный оператор GROUP BY

Вот запрос, который сгенерировало мое приложение

SELECT
 [Campaign].[Title] AS [CampaignTitle]
,CASE WHEN [Task].[Duration] <= @p0 THEN @p1 WHEN [Task].[Duration] >= @p2 AND [Task].[Duration] <= @p3 THEN @p4 ELSE @p5 END AS [9pl1WbY1ZkSvSpel3g4xmw]
,COUNT(1) AS [Ib7ZS4arHkSUWhf4saEtmg]
,SUM(CASE WHEN [Task].[Duration] <= @p6 THEN @p7 ELSE @p8 END) AS [xW1GmttC6kWHsc9QIEPN9w]
FROM [Tasks] AS [Task]
INNER JOIN [Campaigns] AS [Campaign] ON [Campaign].[Id] = [Task].[CampaignId]
INNER JOIN [Users] AS [User] ON [User].[Id] = [Task].[CompletedBy]
INNER JOIN [Results] AS [Result] ON [Result].[Id] = [Task].[ResultId]
WHERE
[Result].[IsCompleted] = @p9 AND ( [User].[LastName] = @p10 OR [User].[LastName] = @p11 )
GROUP BY
[Campaign].[Title]
,CASE WHEN [Task].[Duration] <= @p13 THEN @p14 WHEN [Task].[Duration] >= @p15 AND [Task].[Duration] <= @p16 THEN @p17 ELSE @p18 END
HAVING
COUNT(1) >= @p12
ORDER BY
 [Campaign].[Title]
,CASE WHEN [Task].[Duration] <= @p19 THEN @p20 WHEN [Task].[Duration] >= @p21 AND [Task].[Duration] <= @p22 THEN @p23 ELSE @p24 END

Более того, я попытался вручную заменить имена параметров их значениями. Затем я взял их выходной запрос и выполнил его в SSMS, и он работал без проблем.

Вот как я выполняю запрос

using (SqlConnection connection = new SqlConnection(this.connectionString))
using (SqlDataAdapter sqlAdapter = new SqlDataAdapter(selectCommand))
{
    try
    {
        selectCommand.Connection = connection;

        DataTable table = new DataTable();

        sqlAdapter.Fill(table);

        return table;
    }
    catch (Exception e)
    {
        throw new ReportException(string.Format("{0} {1}", e.Message, e.GetType().FullName));
    }
}

Вот метод, который я использовал для замены параметров их значениями

private string GetPlainQuery(SqlCommand selectCommand)
{
    string output = selectCommand.CommandText;

    for (int i = selectCommand.Parameters.Count - 1; i >= 0; i--)
    {
        var p = selectCommand.Parameters[i];

        string value = p.Value.ToString();

        if (p.SqlDbType == SqlDbType.NChar || p.SqlDbType == SqlDbType.NText || p.SqlDbType == SqlDbType.NVarChar || p.SqlDbType == SqlDbType.Text || p.SqlDbType == SqlDbType.Char || p.SqlDbType == SqlDbType.Date || p.SqlDbType == SqlDbType.DateTime || p.SqlDbType == SqlDbType.SmallDateTime)
        {
            value = string.Format("'{0}'", value.Replace("'", "''"));
        }

        output = output.Replace(p.ParameterName, value);
    }

    return output;
}

Что вызывает эту ошибку? Как я могу это исправить?

ОБНОВЛЕНО

Вот запрос после того, как я заменил параметры значениями

SELECT
 [Campaign].[Title] AS [CampaignTitle]
,CASE WHEN [Task].[Duration] <= 100 THEN '<100' WHEN [Task].[Duration] >= 100 AND [Task].[Duration] <= 200 THEN 'BETWEEN 100 AND 200' ELSE '>200' END AS [9pl1WbY1ZkSvSpel3g4xmw]
,COUNT(1) AS [Ib7ZS4arHkSUWhf4saEtmg]
,SUM(CASE WHEN [Task].[Duration] <= 100 THEN 1 ELSE 0 END) AS [xW1GmttC6kWHsc9QIEPN9w]
FROM [Tasks] AS [Task]
INNER JOIN [Campaigns] AS [Campaign] ON [Campaign].[Id] = [Task].[CampaignId]
INNER JOIN [Users] AS [User] ON [User].[Id] = [Task].[CompletedBy]
INNER JOIN [Results] AS [Result] ON [Result].[Id] = [Task].[ResultId]
WHERE
[Result].[IsCompleted] = 1 AND ( [User].[LastName] = 'Yo' OR [User].[LastName] = 'Smith' )
GROUP BY
 [Campaign].[Title]
,CASE WHEN [Task].[Duration] <= 100 THEN '<100' WHEN [Task].[Duration] >= 100 AND [Task].[Duration] <= 200 THEN 'BETWEEN 100 AND 200' ELSE '>200' END
HAVING
COUNT(1) >= 0
ORDER BY
 [Campaign].[Title]
,CASE WHEN [Task].[Duration] <= 100 THEN '<100' WHEN [Task].[Duration] >= 100 AND [Task].[Duration] <= 200 THEN 'BETWEEN 100 AND 200' ELSE '>200' END

person Junior    schedule 28.07.2016    source источник
comment
Ошибка говорит Tasks.Duration, но я вижу только Task.Duration в вашем SQL-запросе. Есть ли опечатки, которые упускаются из виду?   -  person Jonathon Ogden    schedule 28.07.2016
comment
Можете ли вы дать нам нормальный запрос, в том числе без параметров.   -  person Surendra    schedule 28.07.2016
comment
@JonathonOgden Я думаю, это потому, что таблица Tasks имеет псевдоним Task.   -  person juharr    schedule 28.07.2016
comment
@JonathonOgden да, я видел это, но не уверен, откуда это. Я вставил запрос точно так же, как скопировал его из VS.   -  person Junior    schedule 28.07.2016
comment
Я бы, вероятно, сделал подзапрос, который переводил бы продолжительность в 3 желаемых диапазона, а затем сгруппировал бы это.   -  person juharr    schedule 28.07.2016
comment
@MikeA Вы вообще использовали SQL Server Profiler, чтобы увидеть, как окончательный запрос представляется в SQL Server?   -  person Jonathon Ogden    schedule 28.07.2016
comment
Разве вы не должны переводить первый диапазон в ‹=100 или вам следует изменить логику, чтобы она соответствовала? В любом случае у вас есть ‹= 100, а затем ›= 100, и он будет использовать первый, когда он равен 100, и на самом деле только один должен проверяться на равенство.   -  person juharr    schedule 28.07.2016


Ответы (2)


Я предполагаю, что ошибка связана с тем, что ваш оператор case в списке выбора не совпадает с оператором в вашей группе. Что я обычно делаю, так это разрешаю эти столбцы в подзапросе, чтобы было легче читать и поддерживать внешний запрос.

person Joe C    schedule 28.07.2016
comment
Если вы посмотрите на мой запрос, вы увидите единственное отличие в выбранном столбце, а группа - это имя параметра, но значение такое же. Может ли это быть проблемой? - person Junior; 28.07.2016
comment
@MikeA Зачем использовать разные параметры? Разве вы не знаете, что вы можете использовать параметры более одного раза в запросе? - person juharr; 28.07.2016
comment
@juharr да, я не знаю, могу ли я повторно использовать один и тот же параметр! спасибо за эту заметку. Но может ли это быть причиной этой ошибки? - person Junior; 28.07.2016
comment
Я не вижу никакой другой причины. Вероятно, запрос анализируется до разрешения параметров. - person Joe C; 28.07.2016
comment
@MikeA Да, потому что он проверит перед заменой параметров значениями. Это одна из точек параметров, поэтому он может анализировать запрос, и план будет повторно использоваться для разных наборов параметров. - person juharr; 28.07.2016
comment
Я сделаю это обновление и дам вам знать, если это сработало. - person Junior; 28.07.2016
comment
Оно работало завораживающе. Я добавлю ответ с резюме, чтобы помочь другим. - person Junior; 28.07.2016

Чего мне здесь не хватало, так это того, что фреймворк сначала проверяет запрос, прежде чем заменяет параметры.

Поскольку имена параметров в select и в group by различаются, фреймворк предполагает, что они имеют разные значения, что и вызывает проблему.

Решение состояло в том, чтобы повторно использовать одно и то же имя параметра, чтобы дать платформе уверенность в том, что значения одинаковы.

person Junior    schedule 28.07.2016