命名窗口

分析函数的 OVER 子句可以引用命名窗口,此窗口封装了一个或多个窗口子句:窗口分区 (PARTITION BY) 子句和(可选)窗口顺序 (ORDER BY) 子句。编写通过类似的 OVER 子句语法调用多个分析函数的查询时,例如,它们使用相同的分区子句,则命名窗口非常有用。

查询按如下方式命名窗口:

WINDOW window‑name AS ( window-partition-clause [window-order-clause] );

同一个查询可以命名和引用多个窗口。在同一个查询中,所有窗口名称都必须是唯一的。

示例

以下查询调用了两个分析函数,即 RANKDENSE_RANK。因为两个函数使用同一个分区和顺序子句,查询对指定这两个子句的 w 窗口进行了命名。两个函数引用了此窗口,如下所示:

=> SELECT employee_region region, employee_key, annual_salary,
     RANK() OVER w Rank,
     DENSE_RANK() OVER w "Dense Rank"
     FROM employee_dimension WINDOW w AS (PARTITION BY employee_region ORDER BY annual_salary);
              region              | employee_key | annual_salary | Rank | Dense Rank
----------------------------------+--------------+---------------+------+------------
 West                             |         5248 |          1200 |    1 |          1
 West                             |         6880 |          1204 |    2 |          2
 West                             |         5700 |          1214 |    3 |          3
 West                             |         9857 |          1218 |    4 |          4
 West                             |         6014 |          1218 |    4 |          4
 West                             |         9221 |          1220 |    6 |          5
 West                             |         7646 |          1222 |    7 |          6
 West                             |         6621 |          1222 |    7 |          6
 West                             |         6488 |          1224 |    9 |          7
 West                             |         7659 |          1226 |   10 |          8
 West                             |         7432 |          1226 |   10 |          8
 West                             |         9905 |          1226 |   10 |          8
 West                             |         9021 |          1228 |   13 |          9
 West                             |         7855 |          1228 |   13 |          9
 West                             |         7119 |          1230 |   15 |         10
 ...

如果命名窗口忽略了顺序子句,查询的 OVER 子句可以指定自己的顺序子句。例如,您可以修改上一个查询,让每个函数使用不同的顺序子句。命名窗口在定义后仅包括一个分区子句:

=> SELECT employee_region region, employee_key, annual_salary,
    RANK() OVER (w ORDER BY annual_salary DESC) Rank,
    DENSE_RANK() OVER (w ORDER BY annual_salary ASC) "Dense Rank"
    FROM employee_dimension WINDOW w AS (PARTITION BY employee_region);
              region              | employee_key | annual_salary | Rank | Dense Rank
----------------------------------+--------------+---------------+------+------------
 West                             |         5248 |          1200 | 2795 |          1
 West                             |         6880 |          1204 | 2794 |          2
 West                             |         5700 |          1214 | 2793 |          3
 West                             |         6014 |          1218 | 2791 |          4
 West                             |         9857 |          1218 | 2791 |          4
 West                             |         9221 |          1220 | 2790 |          5
 West                             |         6621 |          1222 | 2788 |          6
 West                             |         7646 |          1222 | 2788 |          6
 West                             |         6488 |          1224 | 2787 |          7
 West                             |         7432 |          1226 | 2784 |          8
 West                             |         9905 |          1226 | 2784 |          8
 West                             |         7659 |          1226 | 2784 |          8
 West                             |         7855 |          1228 | 2782 |          9
 West                             |         9021 |          1228 | 2782 |          9
 West                             |         7119 |          1230 | 2781 |         10
 ...

同样地,如果命名窗口包含一个顺序子句,OVER 子句可指定命名窗口也指定一个窗口框架子句。如果无法将命名窗口定义为包含一个窗口框架子句,上述用法会非常有用。

例如,以下查询定义了一个封装分区和顺序子句的窗口。OVER 子句调用此窗口,还包含一个窗口框架子句:

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

递归窗口引用

WINDOW 子句可引用另一个已经命名的窗口。例如,由于命名窗口 w1 是在 w2 之前定义的,因此定义 w2WINDOW 子句可以引用 w1

=> SELECT RANK() OVER(w1 ORDER BY sal DESC), RANK() OVER w2
   FROM EMP WINDOW w1 AS (PARTITION BY deptno), w2 AS (w1 ORDER BY sal);

限制

  • OVER 子句只能引用一个命名窗口。

  • 同一个查询中的每个 WINDOW 子句都必须拥有唯一的名称。