### 12.21.4 命名窗口

[](<>)[](<>)

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

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

对于每个窗口定义，*`窗口名称`*是窗口名称，并且*`窗口规格`*与括号中给出的窗口规范类型相同`超过`条款，如中所述[第 12.21.2 节，“窗口函数概念和语法”](window-functions-usage.html)：

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