如何选择多个列但只按一个列进行分组?

我在使用group by时遇到了问题,我想选择多个列,但只按照一个列进行分组。下面是我尝试的查询语句,但是它给我报错了。
SELECT Rls.RoleName,Pro.[FirstName],Pro.[LastName],Count(UR.[RoleId]) as [Count]
from [b.website-sitecore-core].[dbo].[aspnet_UsersInRoles] UR
inner join [b.website-professional-au].[dbo].[Profile]  Pro
on UR.UserId = Pro.Id
inner join [b.website-sitecore-core].[dbo].[aspnet_Roles] Rls
on Rls.RoleId = UR.RoleId
inner join [b.website-professional-au].[dbo].[Gender] Gn
on gn.Id = pro.GenderId
GROUP BY Rls.RoleName;
3个回答

在SQL Server中,你只能选择作为GROUP BY子句的一部分的列,或者对其他列使用聚合函数。我在这里详细介绍了这个问题。所以你有两个选择: 1. 将额外的列添加到GROUP BY子句中:
GROUP BY Rls.RoleName, Pro.[FirstName], Pro.[LastName]
2. 在相关列上添加一些聚合函数:
SELECT Rls.RoleName, MAX(Pro.[FirstName]), MAX(Pro.[LastName])
第二个解决方案主要是一种权宜之计,也是指示您应该修复关于查询的更一般的问题。

在SQL Server中,你只能选择作为GROUP BY子句的一部分的列,或者对其他列使用聚合函数... 这正是我想要的。谢谢 - Irfan
请注意:这两个选项可能会提供完全错误的结果!GROUP BY A,B,CGROUP BY A相比,可能完全不同。而且,通常我们不能使用某些聚合函数来获取相关列的值。请查看此答案作为解决方案。 - S.Serpooshan
我知道在我的情况下,这两个查询将得到完全相同的结果(始终如此)。但我想知道哪个更高效。假设Rolename是一个表中被连接的主键(因此有索引),而其他列是varchar类型。基本上,max在这里起到什么作用? - Mohit Singh
@MohitSingh: 我建议你提出一个新问题。 - Lukas Eder

注意:此答案旨在作为@Lukas Eder's answer的补充

如果字段 SELECT 中存在多个值,但你希望使用 GROUP BY 对其分组,则可以选择获取匹配的顶部行,而不是等待聚合(MAX)返回。

SELECT i.RoleName, i.*
FROM Rls JOIN 
(SELECT TOP 1 R.Rolename, Pro.FirstName, Pro.LastName FROM Rls as R JOIN Pro ON ... ) as i
     ON i.Rolename=Rls.RoleName
如果你想让所有的值都在其他列中返回,但又希望将其合并为一个条目,请参考此链接:https://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/

我曾经遇到过同样的问题,当我想要按照事务表中的某个内容进行分组时,时间戳是最新条目。例如,一个审计表,其中包含用户名、一些唯一标识符和时间戳。 因此,我可以通过以下方式获取所有对象上次更新的最大时间戳:
  SELECT max(timeStamp) AS timeStamp, someUniqueId 
  FROM tableName
  GROUP BY someUniqueId 
但是我无法提取其他列,比如用户名...我设法通过从主表中选择并在内部连接中使用上述结果集来解决这个问题:
  SELECT a.someUniqueId, a.timeStamp, a.username
  FROM tableName a
  INNER JOIN (
    SELECT max(timeStamp) AS timeStamp, someUniqueId 
    FROM tableName
    GROUP BY someUniqueId 
  ) b ON a.someUniqueId = b.someUniqueId AND a.timeStamp = b.timeStamp