1

I am working on a project that will allow the users to build a query just by selecting columns.

My application seems to be working fine and generating the correct queries. But when I execute the query I get the following exception

Column 'Tasks.Duration' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

What does not make since here is that my query actually includes the correct GROUP BY statement

Here is the query that my application generated

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

Better yet, I tried to manually replace the parameter names with parameter value. Then I took they output query and I executed it in SSMS and it worked with no problems.

This is how I execute the query

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));
    }
}

Here is the method that I used to replace the parameters with their values

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;
}

What is causing this error? How can I fix it?

UPDATED

Here is the query after I replaced the parameters with the values

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
7
  • 1
    The error says Tasks.Duration, yet I see only Task.Duration in your SQL query. Are there typos being overlooked? Commented Jul 28, 2016 at 18:11
  • Can you give us the normal query, without the parameters as well. Commented Jul 28, 2016 at 18:12
  • @JonathonOgden I think it's because the table Tasks is being aliased as Task. Commented Jul 28, 2016 at 18:13
  • 1
    I'd probably do a subquery that translated duration to the 3 desired ranges, then group on that. Commented Jul 28, 2016 at 18:16
  • 1
    @MikeA Have you used SQL Server Profiler at all to see how the final query is presented to SQL Server? Commented Jul 28, 2016 at 18:18

2 Answers 2

3

My guess is that the error is due to your case statement in the select list is not the same as the one in your group by. What I usually do is resolve these columns in a subquery so that it is easier to read and maintain the outer query.

Sign up to request clarification or add additional context in comments.

7 Comments

If you look at my query you will see the only different in the selected column and the group by is the parameter name but the value is the same. Could this be an issue?
@MikeA Why use different parameters? Are you not aware that you can use parameters more than once in a query?
@juharr yes I am not aware that I can resuse the same parameter! thank you for that note. But could that be causing this error?
I cant see any other reason. The query is likely being parsed before the parameters are being resolved.
@MikeA Yes because it will do the check before replacing the parameters with the values. That's one of the points of paramters, so it can parse the query and the plan will get reused for different sets of parameters.
|
0

The thing that I was missing here is that the framework will first validate they query before it replaces the parameters.

Since the parameter names are different in the select and in the group by, the framework assume they have different value which causes the problem.

The solution was to reuse the same parameter name to give the framework assurance that the values are the same.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.