报告聚合

采用 window-frame-clause 的某些分析函数是报告聚合函数。通过这些函数,您可以比较分区的聚合值与明细行,而不使用相关子查询或联接。

如果结合空 OVER() 子句使用窗口聚合,分析函数将用作报告函数,而且整个输入会被视为一个分区。

关于标准差函数和方差函数

使用标准差函数时,较小的标准差表示数据点通常非常接近于平均值,而较大的标准差表示数据点分散在一个较大的值范围内。

标准差通常用图形表示,而分布式标准差为典型的钟形曲线。

方差函数会衡量一组数值的分散距离。

示例

将报告聚合的窗口看作是定义为 UNBOUNDED PRECEDING 和 UNBOUNDED FOLLOWING 的窗口。忽略 window-order-clause 会使分区中的所有行也位于窗口中(报告聚合)。

=> SELECT deptno, sal, empno, COUNT(sal)
  OVER (PARTITION BY deptno) AS COUNT FROM emp;
 deptno | sal | empno | count
--------+-----+-------+-------
     10 | 101 |     1 |     2
     10 | 104 |     4 |     2
------------------------------
     20 | 110 |    10 |     6
     20 | 110 |     9 |     6
     20 | 109 |     7 |     6
     20 | 109 |     6 |     6
     20 | 109 |     8 |     6
     20 | 100 |    11 |     6
------------------------------
     30 | 105 |     5 |     3
     30 | 103 |     3 |     3
     30 | 102 |     2 |     3
(11 rows)

如果上述查询中的 OVER() 子句包含 window-order-clause (例如 ORDER BY sal),它将变为包含 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 默认窗口的移动窗口(窗口聚合)查询:

=> SELECT deptno, sal, empno, COUNT(sal)  OVER (PARTITION BY deptno ORDER BY sal) AS COUNT FROM emp;
 deptno | sal | empno | count
--------+-----+-------+-------
     10 | 101 |     1 |     1
     10 | 104 |     4 |     2
------------------------------
     20 | 100 |    11 |     1
     20 | 109 |     7 |     4
     20 | 109 |     6 |     4
     20 | 109 |     8 |     4
     20 | 110 |    10 |     6
     20 | 110 |     9 |     6
------------------------------
     30 | 102 |     2 |     1
     30 | 103 |     3 |     2
     30 | 105 |     5 |     3
(11 rows)

LAST_VALUE 怎么样?

您可能会想为什么您不能只使用 LAST_VALUE() 分析函数。

例如,对于每个员工,获取部门中最高薪水:

=> SELECT deptno, sal, empno,LAST_VALUE(empno) OVER (PARTITION BY deptno ORDER BY sal) AS lv FROM emp;
![](/images/reporting-aggregates2.png)

受默认窗口语义影响,LAST_VALUE 并非总是会返回分区的最后一个值。如果在分析子句中忽略 window-frame-clause,则 LAST_VALUE 会在默认窗口中运行。因此,结果似乎并不直观,因为函数没有返回当前分区的最后一个值。它只返回了窗口的最后一个值,并且此值随当前正在处理的输入行而不断变化。

请记住默认窗口:

OVER (PARTITION BY deptno ORDER BY sal)

等同于:

OVER(PARTITION BY deptno ORDER BY salROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

如果您要返回分区的最后一个值,请使用 UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。

=> SELECT deptno, sal, empno, LAST_VALUE(empno)
OVER (PARTITION BY deptno ORDER BY sal
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lv
FROM emp;
![](/images/reporting-aggregates9.png)

Vertica 建议结合 window-order-clause 使用 LAST_VALUE 以生成具有确定性的结果。

在以下示例中,empno 6、7 和 8 的薪水相同,因此它们位于相邻行中。在本例中,empno 8 首先出现,但不能保证该顺序。

请注意,在上述输出中,最后一个值是 7,它是分区 deptno = 20 的最后一个行。如果各行的顺序不同,则函数会返回不同的值:

此时,最后一个值是 6,它是分区 deptno = 20 的最后一个行。解决方案是将唯一键添加到排序顺序中。即使查询的顺序发生变化,结果也始终相同,因此非常确定。

=> SELECT deptno, sal, empno, LAST_VALUE(empno)
OVER (PARTITION BY deptno ORDER BY sal, empno
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as lv
FROM emp;

请注意行现在如何按 empno 进行排序,这时最后一个值一直是 8,而且无论查询顺序如何都不会造成影响。