可以通过给它们命名来定义窗口,以便在 OVER 子句中引用它们。为此,请使用 WINDOW 子句。如果查询中存在该子句,它将位于 HAVING 和 ORDER BY 子句之间,并具有以下语法:
WINDOW window_name AS (window_spec)
[, window_name AS (window_spec)] ...
对于每个窗口定义, window_name 是窗口名称,而 window_spec 是与 OVER 子句中的窗口规范相同的类型,详见 第 14.20.2 节,“窗口函数概念和语法”:
window_spec:
[window_name] [partition_clause] [order_clause] [frame_clause]
一个 WINDOW 子句对于查询非常有用,其中多个 OVER 子句将定义相同的窗口。相反,您可以定义窗口一次,给它命名,然后在 OVER 子句中引用该名称。考虑以下查询,它定义了多个相同的窗口:
SELECT
val,
ROW_NUMBER() OVER (ORDER BY val) AS 'row_number',
RANK() OVER (ORDER BY val) AS 'rank',
DENSE_RANK() OVER (ORDER BY val) AS 'dense_rank'
FROM numbers;
该查询可以使用 WINDOW 定义窗口一次,并在 OVER 子句中引用该名称:
SELECT
val,
ROW_NUMBER() OVER w AS 'row_number',
RANK() OVER w AS 'rank',
DENSE_RANK() OVER w AS 'dense_rank'
FROM numbers
WINDOW w AS (ORDER BY val);
命名窗口还使得实验窗口定义以查看查询结果的影响变得更加容易。您只需要修改 WINDOW 子句中的窗口定义,而不是多个 OVER 子句定义。
如果 OVER 子句使用 OVER ( 而不是 window_name ...)OVER ,则命名窗口可以通过添加其他子句进行修改。例如,该查询定义了一个包括分区的窗口,并在 window_nameOVER 子句中使用 ORDER BY 以不同的方式修改窗口:
SELECT
DISTINCT year, country,
FIRST_VALUE(year) OVER (w ORDER BY year ASC) AS first,
FIRST_VALUE(year) OVER (w ORDER BY year DESC) AS last
FROM sales
WINDOW w AS (PARTITION BY country);
一个 OVER 子句只能添加命名窗口的属性,而不能修改它们。如果命名窗口定义包括分区、排序或框架属性,则 OVER 子句不能也包括相同种类的属性,否则将发生错误:
-
该构造是允许的,因为窗口定义和引用的
OVER子句不包含相同种类的属性:OVER (w ORDER BY country) ... WINDOW w AS (PARTITION BY country) -
该构造是不允许的,因为
OVER子句指定了PARTITION BY,而命名窗口已经具有PARTITION BY:OVER (w PARTITION BY year) ... WINDOW w AS (PARTITION BY country)
命名窗口的定义本身可以以 window_name 开头。在这种情况下,前向和后向引用是允许的,但不允许循环:
-
这是允许的;它包含前向和后向引用,但不包含循环:
WINDOW w1 AS (w2), w2 AS (), w3 AS (w1) -
这是不允许的,因为它包含一个循环:
WINDOW w1 AS (w2), w2 AS (w3), w3 AS (w1)