简体   繁体   English

尝试使用c#执行查询时SqlCommand返回错误

[英]SqlCommand is returning an error when attempting to execute a query using c#

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. 列'Tasks.Duration'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。

What does not make since here is that my query actually includes the correct GROUP BY statement 这里没有做的是我的查询实际上包含了正确的GROUP BY语句

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. 然后我把它们输出查询,我在SSMS中执行它,它没有任何问题。

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

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. 我的猜测是错误是由于你在选择列表中的case语句与你的组中的case语句不同。 What I usually do is resolve these columns in a subquery so that it is easier to read and maintain the outer query. 我通常做的是在子查询中解析这些列,以便更容易阅读和维护外部查询。

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. 由于参数名称在select和group by中不同,因此框架假设它们具有导致问题的不同值。

The solution was to reuse the same parameter name to give the framework assurance that the values are the same. 解决方案是重用相同的参数名称,以使框架保证值相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM