14.20.4 命名窗口
窗口可以被定义并以名称引用它们,以便在OVER
子句中引用它们。要实现此操作,请使用WINDOW
子句。如果在查询中存在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_name
ORDER BY
在OVER
子句中修改窗口以不同方式:
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)