Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


14.20.4 命名窗口

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

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)