C# 存储过程的SQL GroupBy导致错误

C# 存储过程的SQL GroupBy导致错误,c#,sql,stored-procedures,C#,Sql,Stored Procedures,我有一个快速的问题,为什么我的SQL存储过程不能正常工作。有人能解释一下我的存储过程查询出了什么问题吗? 错误:“每个GROUP BY表达式必须至少包含一个非外部引用的列。” 不能按列参数化分组。从GROUP BY中删除参数@TabGroupBy,不能按列参数化GROUP BY。从GROUP BY中删除参数@TabGroupBy,它永远不会像您尝试的那样工作,因为根据定义,选择部分中的所有列名,以及GROUP BY-子句中的所有列名不能来自@变量。它们必须以纯文本形式编写,因为它们是标识符 这同

我有一个快速的问题,为什么我的SQL存储过程不能正常工作。有人能解释一下我的存储过程查询出了什么问题吗? 错误:“每个GROUP BY表达式必须至少包含一个非外部引用的列。”


不能按列参数化分组。从GROUP BY中删除参数
@TabGroupBy
,不能按列参数化GROUP BY。从GROUP BY

中删除参数
@TabGroupBy
,它永远不会像您尝试的那样工作,因为根据定义
选择部分中的所有列名,以及
GROUP BY
-子句中的所有列名不能来自@变量。它们必须以纯文本形式编写,因为它们是标识符

这同样适用于
FROM
JOIN
子句中的表名+列名

这是因为查询编译器的构建是为了对照数据库中存在的对象检查所有指定的列(以及表、模式等),这需要在运行一行编译代码之前成功。您应该始终记住,在编译时,@-变量还不存在,也不能有值(因为它们还不存在)

解决方案是使用动态SQL。通过在类型为
NVARCHAR(max)
@SQL
变量中构建要执行的实际SQL字符串,然后执行该变量的内容,可以实现所需的功能。EXEC将根据其参数的内容调用SQL查询编译器

示例代码可能不是100%完美,因为我无法运行它,因为您的数据库不可用,但这应该可以帮助您:

DECLARE @SQL NVARCHAR(max) =
    'SELECT ' +
      QUOTENAME(@TabGroupBy) + ' AS ' + QUOTENAME(@TabGroupByName) + ', ' +
      'SUM(Value) AS Sum, ' + 
      '[Unit], ' +
      '[Child_Name] ' +
    'FROM ( ' +
      'SELECT [model_id],[Child_ID],[Property_ID],[DDate],[Hour],[Value] ' +
      'FROM [RP_IRP].[M_PLEXOS].[dat_Generators] ' +
      'where parent_ID = 1 ' +
      '  and child_ID in (9, 357, 358) ' +
      '  and Property_ID in (4, 31) ' +
      ') a ' +
    'inner join [RP_IRP].[M_PLEXOS].[Child_Object] b on a.child_id=b.child_id ' +
    'inner join [M_PLEXOS].[Property] d on d.[Property_ID] = a.[Property_ID] ' +
    'inner join [M_PLEXOS].[Units] e on d.[Unit_ID]=e.[Unit_ID] ' +
    'inner join [M_PLEXOS].[Model_Config] f on a.[Model_id]=f.[Model_id] ' +
    'WHERE Child_Name =  ''' + REPLACE(@SelectedChildValue   , '''', '''''') + ''' ' +
    '  AND Property   =  ''' + REPLACE(@SelectedPropertyValue, '''', '''''') + ''' ' +
    '  AND Unit       =  ''' + REPLACE(@SelectedUnitValue    , '''', '''''') + ''' ' +
    'GROUP BY Child_Name , ' + QUOTENAME(@TabGroupBy) + ', Unit ' +
    'HAVING SUM(Value) > ' + CAST(@MinValue AS VARCHAR(20)) -- assuming @MinValue is INT or FLOAT

EXEC (@SQL)
此代码假定@-变量中可能有引号。如果@变量表示字符串值,请始终使用REPLACE将嵌入的引号加倍,或者更好:使用动态SQL和@参数,请参阅以了解如何做到这一点


对于@变量表示数据库标识符(列名等)的情况,您需要使用示例代码中的
QUOTENAME(…)
,以确保不会发生滥用。

它永远不会像您尝试的那样工作,因为根据定义
选择部分中的所有列名,以及
GROUP BY
-子句中的所有列名不能来自@-变量。它们必须以纯文本形式编写,因为它们是标识符

这同样适用于
FROM
JOIN
子句中的表名+列名

这是因为查询编译器的构建是为了对照数据库中存在的对象检查所有指定的列(以及表、模式等),这需要在运行一行编译代码之前成功。您应该始终记住,在编译时,@-变量还不存在,也不能有值(因为它们还不存在)

解决方案是使用动态SQL。通过在类型为
NVARCHAR(max)
@SQL
变量中构建要执行的实际SQL字符串,然后执行该变量的内容,可以实现所需的功能。EXEC将根据其参数的内容调用SQL查询编译器

示例代码可能不是100%完美,因为我无法运行它,因为您的数据库不可用,但这应该可以帮助您:

DECLARE @SQL NVARCHAR(max) =
    'SELECT ' +
      QUOTENAME(@TabGroupBy) + ' AS ' + QUOTENAME(@TabGroupByName) + ', ' +
      'SUM(Value) AS Sum, ' + 
      '[Unit], ' +
      '[Child_Name] ' +
    'FROM ( ' +
      'SELECT [model_id],[Child_ID],[Property_ID],[DDate],[Hour],[Value] ' +
      'FROM [RP_IRP].[M_PLEXOS].[dat_Generators] ' +
      'where parent_ID = 1 ' +
      '  and child_ID in (9, 357, 358) ' +
      '  and Property_ID in (4, 31) ' +
      ') a ' +
    'inner join [RP_IRP].[M_PLEXOS].[Child_Object] b on a.child_id=b.child_id ' +
    'inner join [M_PLEXOS].[Property] d on d.[Property_ID] = a.[Property_ID] ' +
    'inner join [M_PLEXOS].[Units] e on d.[Unit_ID]=e.[Unit_ID] ' +
    'inner join [M_PLEXOS].[Model_Config] f on a.[Model_id]=f.[Model_id] ' +
    'WHERE Child_Name =  ''' + REPLACE(@SelectedChildValue   , '''', '''''') + ''' ' +
    '  AND Property   =  ''' + REPLACE(@SelectedPropertyValue, '''', '''''') + ''' ' +
    '  AND Unit       =  ''' + REPLACE(@SelectedUnitValue    , '''', '''''') + ''' ' +
    'GROUP BY Child_Name , ' + QUOTENAME(@TabGroupBy) + ', Unit ' +
    'HAVING SUM(Value) > ' + CAST(@MinValue AS VARCHAR(20)) -- assuming @MinValue is INT or FLOAT

EXEC (@SQL)
此代码假定@-变量中可能有引号。如果@变量表示字符串值,请始终使用REPLACE将嵌入的引号加倍,或者更好:使用动态SQL和@参数,请参阅以了解如何做到这一点


对于@变量表示数据库标识符(列名等)的情况,您需要使用示例代码中的
QUOTENAME(…)
,以确保不会发生滥用。

@niksrinivas,称为别名;它是necessary@CaiusJard谢谢,我不知道@niksrinivas被称为别名;它是necessary@CaiusJard谢谢,我不知道!但是@TabGroupBy是groupby的一部分,因此如果我删除它,查询将不再正确。你还有其他建议吗?谢谢。@TabGroupBy不是GroupBy的一部分;该错误消息告诉您它不能是group by的一部分。你必须移除它。在任何情况下,变量都是一个固定的单值,就像一个字符串
'Hello World'
-按常量分组是不可操作的。将列名放入
@tabGroupBy
不会导致查询按该列分组,就像说
DECLARE@tableName VARCHAR='tblPerson';选择*FROM@tableName
将从tblPerson中提取所有行-有些地方不能使用变量。。这是其中之一。如果要运行此查询,必须将其删除。如果您试图将列名放入其中,并希望查询按其分组,则可以将所有可能的列预编程到以下情况中:
group by x,case when@y='ChildID',ChildID when@y='ParentID',ParentID…
或使用动态sql,但是,不能将标识符加载到任何语言的字符串变量中,然后将该变量视为标识符。除了javascript;)但是@TabGroupBy是groupby的一部分,因此如果我删除它,查询将不再正确。你还有其他建议吗?谢谢。@TabGroupBy不是GroupBy的一部分;该错误消息告诉您它不能是group by的一部分。你必须移除它。在任何情况下,变量都是一个固定的单值,就像一个字符串
'Hello World'
-按常量分组是不可操作的。将列名放入
@tabGroupBy
不会导致查询按该列分组,就像说
DECLARE@tableName VARCHAR='tblPerson';选择*FROM@tableName
将从tblPerson中提取所有行-有som