

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 聚合函数
<a name="sql-reference-aggregate-functions"></a>

聚合函数返回的不是根据单个行计算得出的结果，而是根据有限行集中包含的聚合数据或有限行集的相关信息计算得出的结果。聚合函数可能出现在以下任何一项中：
+ [SELECT 子句](sql-reference-select-clause.md)的 <selection list> 部分
+ [ORDER BY 子句](sql-reference-order-by-clause.md)
+ [HAVING 子句](sql-reference-having-clause.md)

聚合函数不同于[分析函数](sql-reference-analytic-functions.md)，后者始终相对于必须指定的窗口进行计算，因此不能出现在 HAVING 子句中。本主题后面的表格中列出了其他区别。

使用聚合函数对表执行聚合查询和对流执行聚合查询的操作略有不同，如下所示。如果对表执行的聚合查询包含 GROUP BY 子句，则聚合函数会为输入行集中的每个组返回一个结果。缺少显式 GROUP BY 子句等同于 GROUP BY ()，只会为整个输入行集返回一个结果。

对于流，聚合查询必须在基于行时间的单调表达式上包含一个显式 GROUP BY 子句。否则，唯一的组就是整个流，永远不会结束，因此无法报告任何结果。基于单调表达式添加 GROUP BY 子句会将流分成在时间上连续的有限行集，然后可以聚合每个此类行集并生成相应报告。

每当一个会更改单调分组表达式值的行到达时，就会启动一个新组，而前一组被视为已完成。然后，Amazon Kinesis Data Analytics 应用程序会输出聚合函数的值。请注意，GROUP BY 子句还可能包括其他非单调表达式，在这种情况下可能会为每个行集生成多个结果。

对流执行聚合查询通常称为流式聚合，这与在[分析函数](sql-reference-analytic-functions.md)和[流的窗口式聚合](sql-reference-windowed-aggregation-stream.md)中讨论的窗口式聚合不同。有关 stream-to-stream联接的更多信息，请参阅[JOIN 子句](sql-reference-join-clause.md)。

如果输入行在用作数据分析函数输入的列中包含 `null`，则数据分析函数将忽略该行（COUNT 除外）。


**聚合函数和分析函数之间的区别**  

| 函数类型 | 输出 | 使用的行或窗口 | 注意 | 
| --- | --- | --- | --- | 
|  聚合函数  |  每组输入行对应一个输出行。  |  所有输出列都是根据同一窗口或同一组行计算的。  |  流式聚合中不允许使用 COUNT DISTINCT。不允许使用以下类型的语句： SELECT COUNT(DISTINCT x) ... FROM ... GROUP BY ...  | 
|  [分析函数](sql-reference-analytic-functions.md)  |  每个输入行对应一个输出行。  |  可以使用不同窗口或分区计算每个输出列。  |  COUNT DISTINCT 不能用作[分析函数](sql-reference-analytic-functions.md)或用在窗口式聚合中。  | 

## 流式聚合和行时间边界
<a name="w2aac22b7c21"></a>

通常，当一个会更改 GROUP BY 中单调表达式值的行到达时，聚合查询就会生成一个结果。例如，如果查询按 FLOOR(rowtime TO MINUTE) 进行分组，而且当前行的行时间为 9:59.30，则行时间为 10:00.00 的新行将触发结果。

或者，可以使用行时间边限来推进单调表达式，使查询能够返回结果。例如，如果查询按 FLOOR(rowtime TO MINUTE) 进行分组，而且当前行的行时间为 9:59.30，则在传入的行时间边界为 10:00.00 时，查询会返回结果。

## 聚合函数列表
<a name="w2aac22b7c23"></a>

Amazon Kinesis Data Analytics 支持以下聚合函数：
+ [AVG](sql-reference-avg.md)
+ [COUNT](sql-reference-count.md)
+ [COUNT\$1DISTINCT\$1ITEMS\$1TUMBLING 函数](count-distinct-items.md)
+ [EXP\$1AVG](sql-reference-exp-avg.md)
+ [FIRST\$1VALUE](sql-reference-first-value.md)
+ [LAST\$1VALUE](sql-reference-last-value.md)
+ [MAX](sql-reference-max.md)
+ [MIN](sql-reference-min.md)
+ [SUM](sql-reference-sum.md)
+ [TOP\$1K\$1ITEMS\$1TUMBLING 函数](top-k.md)



以下 SQL 使用 AVG 聚合函数作为查询的一部分来查找所有员工的平均年龄：

```
SELECT
    AVG(AGE) AS AVERAGE_AGE
FROM SALES.EMPS;
```

结果：


| AVERAGE\$1AGE | 
| --- | 
|  38  | 



要查找每个部门员工的平均年龄，我们可以在查询中添加一个显式 GROUP BY 子句：

```
SELECT
    DEPTNO,
    AVG(AGE) AS AVERAGE_AGE
FROM SALES.EMPS
GROUP BY DEPTNO;
```

返回值:


| DEPTNO | AVERAGE\$1AGE | 
| --- | --- | 
|  10  |  30  | 
|  20  |  25  | 
|  30  |  40  | 
|  40  |  57  | 

## 对流执行的聚合查询的示例（流式聚合）
<a name="w2aac22b7c25"></a>

在此示例中，假设下表中的数据流经名为 WEATHERSTREAM 的流。


| ROWTIME | CITY | TEMP | 
| --- | --- | --- | 
|  2018-11-01 01:00:00.0  |  丹佛  |  29  | 
|  2018-11-01 01:00:00.0  |  安克雷奇  |  2  | 
|  2018-11-01 06:00:00.0  |  迈阿密  |  65  | 
|  2018-11-01 07:00:00.0  |  丹佛  |  32  | 
|  2018-11-01 09:00:00.0  |  安克雷奇  |  9  | 
|  2018-11-01 13:00:00.0  |  丹佛  |  50  | 
|  2018-11-01 17:00:00.0  |  安克雷奇  |  10  | 
|  2018-11-01 18:00:00.0  |  迈阿密  |  71  | 
|  2018-11-01 19:00:00.0  |  丹佛  |  43  | 
|  2018-11-02 01:00:00.0  |  安克雷奇  |  4  | 
|  2018-11-02 01:00:00.0  |  丹佛  |  39  | 
|  2018-11-02 07:00:00.0  |  丹佛  |  46  | 
|  2018-11-02 09:00:00.0  |  安克雷奇  |  3  | 
|  2018-11-02 13:00:00.0  |  丹佛  |  56  | 
|  2018-11-02 17:00:00.0  |  安克雷奇  |  2  | 
|  2018-11-02 19:00:00.0  |  丹佛  |  50  | 
|  2018-11-03 01:00:00.0  |  丹佛  |  36  | 
|  2018-11-03 01:00:00.0  |  安克雷奇  |  1  | 



如果要查找每天任意地方（全球范围内，不分城市）记录的最低和最高温度，则可以分别使用聚合函数 MIN 和 MAX 来计算最低和最高温度。要表示我们每天需要此类信息（以及要提供单调表达式作为 GROUP BY 子句的参数），我们使用 FLOOR 函数将每个行的行时间向下取整为最近一天：

```
SELECT STREAM
    
    FLOOR(WEATHERSTREAM.ROWTIME to DAY) AS FLOOR_DAY,  
    MIN(TEMP) AS MIN_TEMP,
    MAX(TEMP) AS MAX_TEMP
FROM WEATHERSTREAM

GROUP BY FLOOR(WEATHERSTREAM.ROWTIME TO DAY);
```

聚合查询的结果见下表。


| FLOOR\$1DAY | MIN\$1TEMP | MAX\$1TEMP | 
| --- | --- | --- | 
|  2018-11-01 00:00:00.0  |  2  |  71  | 
|  2018-11-02 00:00:00.0  |  2  |  56  | 



尽管示例数据确实包括 2018-11-03 的温度测量值，但没有这一天对应的行。这是因为在知道 2018-11-03 对应的所有行都到达之前，无法聚合这一天对应的行，而且只有在行时间为 2018-11-04 00:00:00.0（或更晚）或行时间边界为 2018-11-04 00:00:00.0（或更晚）的行到达时，才会进行聚合。如果其中任何一个到达，则下一个结果将如下表所示。


| FLOOR\$1DAY | MIN\$1TEMP | MAX\$1TEMP | 
| --- | --- | --- | 
|  2018-11-03 00:00:00.0  |  1  |  36  | 

假设我们不是要查找每天的全球最低和最高气温，而是要查找每天每个城市的最低、最高和平均温度。为此，我们使用 SUM 和 COUNT 聚合函数来计算平均值，然后将 CITY 添加到 GROUP BY 子句中，如下所示：

```
SELECT STREAM
    FLOOR(WEATHERSTREAM.ROWTIME TO DAY) AS FLOOR_DAY,
    
    CITY,
    MIN(TEMP) AS MIN_TEMP,
    MAX(TEMP) AS MAX_TEMP,
    SUM(TEMP)/COUNT(TEMP) AS AVG_TEMP
FROM WEATHERSTREAM
GROUP BY FLOOR(WEATHERSTREAM.ROWTIME TO DAY), CITY;
```

聚合查询的结果见下表。


| FLOOR\$1DAY | CITY | MIN\$1TEMP | MAX\$1TEMP | AVG\$1TEMP | 
| --- | --- | --- | --- | --- | 
|  2018-11-01 00:00:00.0  |  安克雷奇  |  2  |  10  |  7  | 
|  2018-11-01 00:00:00.0  |  丹佛  |  29  |  50  |  38  | 
|  2018-11-01 00:00:00.0  |  迈阿密  |  65  |  71  |  68  | 
|  2018-11-02 00:00:00.0  |  安克雷奇  |  2  |  4  |  3  | 
|  2018-11-02 00:00:00.0  |  丹佛  |  39  |  56  |  47  | 



在本例中，当新一天的温度测量值对应的行到达时，会触发聚合前一天的数据，按 CITY 进行分组，然后为这一天的测量值中包含的每个城市生成一行。

同样，在 2018-11-04 的任何实际测量值出来之前，可以使用行时间边界 2018-11-04 00:00:00.0 来生成 2018-11-03 的结果，如下表所示。


| FLOOR\$1DAY | CITY | MIN\$1TEMP | MAX\$1TEMP | AVG\$1TEMP | 
| --- | --- | --- | --- | --- | 
|  2018-11-03 00:00:00.0  |  安克雷奇  |  1  |  1  |  1  | 
|  2018-11-03 00:00:00.0  |  丹佛  |  36  |  36  |  36  | 