2

在 Querying MS SQL Server 2012 (Training Kit) for Exam 70-461 一书中,它谈到GROUP BY了逻辑处理中的查询阶段:

此查询的最终结果有一行代表每个组 (除非被过滤掉)。因此,在当前分组阶段之后发生的所有阶段中的表达式都有一定的限制。在后续阶段处理的所有表达式必须保证每个组有一个值。如果您从 GROUP BY 列表中引用一个元素(例如,国家/地区),您已经有了这样的保证,因此允许这样的引用。但是,如果要引用不属于 GROUP BY 列表的元素(例如 empid),则它必须包含在 MAX 或 SUM 等聚合函数中。这是因为单个组内的元素中可能有多个值,并且保证只返回一个值的唯一方法是聚合这些值。

然后作者提到了HAVING他使用的步骤COUNT(*) > 1。我的问题是,如果GROUP BY唯一的结果是每组 1 行,那么HAVING使用该单组行的阶段如何过滤掉任何超过 1 行的组......它会保留其中的一半?所以我在这里错过了什么。每个组是否有某种隐藏的 COUNT 列?

查询是:

SELECT country, YEAR(hiredate) AS yearhired, COUNT(*) AS numemployees
FROM HR.Employees
WHERE hiredate >= '20030101'
GROUP BY country, YEAR(hiredate)
HAVING COUNT(*) > 1
ORDER BY country , yearhired DESC;

请解惑。

4

1 回答 1

0

如果作者在GROUP BY他指的是结果集中每组一行,那么当他指的是每组的行时,HAVING他指的是输入。

想象一下这个简单的数据集

Col1    Col2    Value
----------------------
  a       a       1
  a       b       1
  a       b       1
  a       b       2
  a       c       1
  a       c       5

如您所见,(Col1, Col2) 有 3 个不同的元组 - (a, a), (a, b), (a, c),因此如果您 GROUP BY Col1, Col2 您将在您的结果(每组一个)。

SELECT  Col1, Col2
FROM    T
GROUP BY Col1, Col2;

Col1    Col2    
-------------
  a       a   
  a       b   
  a       c  

这就是作者在说“每组一行”时所指的内容。

但是,再次展开您可以看到有两行包含元组 (a, b),另外两行包含 (a, c) - 所以每个输入行有两个输入行,这就是COUNT(*)指代的内容,而不是数字结果集中的行数。

任何聚合函数(无论是在有还是在选择中)都与 GROUP BY同时计算,而不是在它们各自的部分(HAVING、SELECT)。它们是相同的操作,这就是在选择或拥有之前保持组中行数的知识的方式。

Stackoverflow 上有很好的答案,解释了聚合如何在幕后工作以供进一步阅读,所以我不会在这里重复。

于 2013-11-08T13:07:52.777 回答