GROUP BY子句

  GROUP BY阶段可以将WHERE逻辑查询处理阶段返回的行按“组”进行组合。每个组由在GROUP BY子句中指定的各元素决定。例如,以下代码所示查询的GROUP BY子句就使用了empid和YEAR(orderdate)元素:

 SELECT empid,YEAR(orderdate) AS orderyear,COUNT(*) AS numorders
  FROM Sales.Orders
  WHERE custid=71
 GROUP BY empid,YEAR(orderdate);

  

  这意味着对于WHERE阶段返回的数据中出现的每个雇员ID和订单年份值的唯一组合,在GROUP BY阶段将会为其生成一个组。表达式YEAR(orderdate)会调用YEAR函数,只返回orderdate列的年份部分。

  如果上面的代码没有GROUP BY子句,并且去掉COUNT(*) AS numorders字段,WHERE子句将返回31行数据,其中有16对雇员ID和订单年份的唯一组合。这样,GROUP BY阶段将创建16个组,并把从WHERE阶段返回的31行数据和相应的组关联起来。

  如果查询涉及到分组,那么GROUP BY阶段之后的所有阶段(包括HAVING、SELECT,以及ORDER BY)的操作对象将是组,而不是单独的行。每个组最终也表示为查询结果集中的一行。这意味着在GROUP BY阶段之后处理的子句中指定的所有表达式务必保证为每个组返回一个标量(单值)。

  以GROUP BY列表中的元素为基础的表达式满足这一要求,因为按照定义,在每个组中各GROUP BY元素只唯一出现一次。因此,在GROUP BY阶段之后处理的子句(例如SELECT子句)中,可以引用诸如empid和YEAR(orderdate)之类的表达式。

  因为聚合函数只为每个组返回一个值,所以一个元素如果不在GROUP BY列表中出现,就只能作为聚合函数(COUNT、SUM、AVG、MIN,以及MAX)的输入。例如,以下查询返回每个雇员在某个订单年份中的订单数量和总运费:

 SELECT empid,YEAR(orderdate) AS orderyear,SUM(freight) AS totalfreight,COUNT(*) AS numorders
 FROM Sales.Orders
 WHERE custid=71
 GROUP BY empid,YEAR(orderdate);

  

  表达式SUM(freight)返回每组中所有运费值的总和,而函数COUNT(*)则返回每组中行的个数(在这个例子中代表订单的数量)。如果试图引用不再GROUP BY列表中出现的属性(例如freight),而且也没有将其作为GROUP BY子句之后处理的任何子句中聚合函数的输入,SQL Server引擎就会报错(在这种情况下,无法保证表达式为每个组返回的值是唯一的)。例如,以下查询将失败:

 SELECT empid,YEAR(orderdate) AS orderyear,freight,COUNT(*) AS numorders
 FROM Sales.Orders
 WHERE custid=71
 GROUP BY empid,YEAR(orderdate);

  

  SQL Server将生成以下错误信息:

消息 8120,级别 16,状态 1,第 1 行
选择列表中的列 'Sales.Orders.freight' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。

  

  所有的聚合函数都会忽略NULL值,只有一个例外——COUNT(*)。例如,假设一个组有5行,其qty列的值分别为30、10、NULL、10、10.表达式COUNT(*)将返回5,因为这个组中有5行,而COUNT(qty)则返回4,因为只有4行已知值。如果只想处理不重复的已知值,可以在聚合函数的圆括号中指定DISTINCT关键字。例如,表达式COUNT(DISTINCT qty)将返回2,因为已知值中只有2个不重复的取值。在其他函数中也可以使用DISTINCT关键字。例如,表达式SUM(qty)将返回60,而表达式SUM(DISTINCT qty)则返回40.表达式AVG(qty)将返回15,而表达式AVG(DISTINCT qty)则返回20。作为一个在聚合函数中使用DISTINCT选项的完整查询例子,以下代码返回每个雇员每年受理过的不重复(不同)的客户数量。

 SELECT empid,YEAR(orderdate) AS orderyear,COUNT(DISTINCT custid) AS numcusts
 FROM Sales.Orders
 GROUP BY empid,YEAR(orderdate);

  

原文地址:https://www.cnblogs.com/ShaYeBlog/p/2697069.html