# 12.21.4 命名窗口

可以定义 Windows 并为其命名以在其中引用它们超过条款。为此,请使用窗户条款。如果出现在查询中,则窗户子句介于拥有订购方式子句,并具有以下语法:

WINDOW window_name AS (window_spec)
    [, window_name AS (window_spec)] ...

对于每个窗口定义,*窗口名称是窗口名称,并且窗口规格*与括号中给出的窗口规范类型相同超过条款,如中所述第 12.21.2 节,“窗口函数概念和语法”

window_spec:
    [window_name] [partition_clause] [order_clause] [frame_clause]

一种窗户子句对于多个查询很有用超过否则,子句将定义相同的窗口。相反,您可以定义一次窗口,给它一个名称,然后在超过条款。考虑这个查询,它多次定义同一个窗口:

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;

查询可以通过使用更简单地编写窗户定义一次窗口并在超过条款:

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);

命名窗口还可以更轻松地试验窗口定义以查看对查询结果的影响。您只需要修改窗口定义窗户子句,而不是多个超过条款定义。

如果超过子句使用超过 (*窗口名称* ...)而不是超过 *窗口名称*,命名窗口可以通过添加其他子句来修改。例如,此查询定义了一个包含分区的窗口,并使用订购方式在里面超过以不同方式修改窗口的子句:

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 (w ORDER BY country)
    ... WINDOW w AS (PARTITION BY country)
    
  • 这种构造是不允许的,因为超过条款规定分区方式对于已经有的命名窗口分区方式

    OVER (w PARTITION BY year)
    ... WINDOW w AS (PARTITION BY country)
    

    命名窗口的定义本身可以以*窗口名称*.在这种情况下,允许向前和向后引用,但不允许循环:

  • 这是允许的;它包含前向和后向引用,但没有循环:

    WINDOW w1 AS (w2), w2 AS (), w3 AS (w1)
    
  • 这是不允许的,因为它包含一个循环:

    WINDOW w1 AS (w2), w2 AS (w3), w3 AS (w1)