SELECT - WINDOW 子句 (Transact-SQL)

适用于: Microsoft Fabric 中的 SQL Server 2022 (16.x) 及更高版本 Azure SQL 数据库Azure SQL 托管实例SQL 数据库

子句中的 WINDOW 命名窗口定义确定在窗口函数之前行集的分区和排序,该函数使用子句中的 OVER 窗口。

子 WINDOW 句需要数据库兼容性级别 160 或更高版本。 如果数据库兼容性级别低于160,则数据库引擎无法使用子句执行查询WINDOW。

可以在视图或数据库属性中 sys.databases 检查兼容性级别。 可以使用以下命令更改数据库的兼容级别:

ALTER DATABASE DatabaseName
SET COMPATIBILITY_LEVEL = 160;

Transact-SQL 语法约定

Syntax

WINDOW window_name AS (
       [ reference_window_name ]
       [ <PARTITION BY clause> ]
       [ <ORDER BY clause> ]
       [ <ROW or RANGE clause> ]
      )

<PARTITION BY clause> ::=
PARTITION BY value_expression , ... [ n ]

<ORDER BY clause> ::=
ORDER BY order_by_expression
    [ COLLATE collation_name ]
    [ ASC | DESC ]
    [ , ...n ]

<ROW or RANGE clause> ::=
{ ROWS | RANGE } <window frame extent>

Arguments

window_name

定义的窗口规范的名称。 子句中的 OVER 窗口函数使用此名称来引用窗口规范。 窗口名称必须符合标识符的规则。

reference_window_name

当前窗口引用的窗口的名称。 引用的窗口必须是子句中定义的窗口之 WINDOW 一。

其他参数包括:

  • PARTITION BY:将查询结果集分为多个分区。

  • ORDER BY:定义结果集的每个分区中行的逻辑顺序。

  • ROWS/RANGE:通过指定分区中的起点和终点来限制分区中的行数。

有关参数的更具体的详细信息,请参阅 SELECT - OVER 子句。

Remarks

可以在子句中 WINDOW 定义多个命名窗口。

可以使用window_nameOVER中的命名窗口。 但是,子句中指定的 WINDOW 属性不能在 OVER 子句中重新定义。

当查询使用多个窗口时,一个命名窗口可以使用window_name引用另一个命名窗口。 在这种情况下,必须在引用窗口的窗口定义中指定引用 window_name 。 一个窗口中定义的窗口组件不能由引用它的另一个窗口重新定义。

根据在 window 子句中定义窗口的顺序,允许向前和向后的窗口引用。 换句话说,窗口可能会使用窗口表达式中定义的任何其他窗口(作为 reference_window_name的一部分),而不管它们的定义顺序如何。 不允许在单个窗口中使用循环引用和使用多个窗口引用。

窗口表达式中包含的已定义窗口的新 window_name 的范围包括属于窗口表达式的任何窗口定义,以及 SELECT 包含 window 子句的查询规范或 SELECT 语句的子句。 如果窗口表达式包含在查询表达式的查询规范中,这是一个基本表查询,则新 window_name 的范围还包括 ORDER BY 该查询表达式的表达式(如果有)。

子句中 OVER 具有聚合和分析函数的窗口规范的使用限制适用于 WINDOW 子句。

Examples

本文中的代码示例使用AdventureWorks2025了 、 AdventureWorksDW2025或AdventureWorksLT2025示例数据库,您可以从 Azure Data SQL Samples Repository 的 GitHub 仓库下载。

A. 指定在 window 子句中定义的窗口

以下示例查询显示使用子句中的 OVER 命名窗口。

ALTER DATABASE AdventureWorks2025
SET COMPATIBILITY_LEVEL = 160;
GO

USE AdventureWorks2025;
GO

SELECT ROW_NUMBER() OVER win AS [Row Number],
       p.LastName,
       s.SalesYTD,
       a.PostalCode
FROM Sales.SalesPerson AS s
     INNER JOIN Person.Person AS p
         ON s.BusinessEntityID = p.BusinessEntityID
     INNER JOIN Person.Address AS a
         ON a.AddressID = p.BusinessEntityID
WHERE TerritoryID IS NOT NULL
      AND SalesYTD <> 0
WINDOW win AS (
    PARTITION BY PostalCode ORDER BY SalesYTD DESC
)
ORDER BY PostalCode;

以下查询与上一个查询等效,而不使用 WINDOW 子句。

USE AdventureWorks2025;
GO

SELECT ROW_NUMBER() OVER (
           PARTITION BY PostalCode ORDER BY SalesYTD DESC
       ) AS [Row Number],
       p.LastName,
       s.SalesYTD,
       a.PostalCode
FROM Sales.SalesPerson AS s
     INNER JOIN Person.Person AS p
         ON s.BusinessEntityID = p.BusinessEntityID
     INNER JOIN Person.Address AS a
         ON a.AddressID = p.BusinessEntityID
WHERE TerritoryID IS NOT NULL
      AND SalesYTD <> 0
ORDER BY PostalCode;

结果集如下。

行号 LastName SalesYTD PostalCode
1 Mitchell 4251368.5497 98027
2 Blythe 3763178.1787 98027
3 Carson 3189418.3662 98027
4 Reiter 2315185.611 98027
5 Vargas 1453719.4653 98027
6 Ansman-Wolfe 1352577.1325 98027
1 Pak 4116871.2277 98055
2 瓦尔基·楚杜卡蒂尔 3121616.3202 98055
3 Saraiva 2604540.7172 98055
4 Ito 2458535.6169 98055
5 Valdez 1827066.7118 98055
6 Mensa-Annan 1576562.1966 98055
7 Campbell 1573012.9383 98055
8 Tsoflias 1421810.9242 98055

B. 在多个 OVER 子句中指定单个窗口

以下示例演示如何定义窗口规范并在子句中 OVER 多次使用它。

ALTER DATABASE AdventureWorks2025
SET COMPATIBILITY_LEVEL = 160;
GO

USE AdventureWorks2025;
GO

SELECT SalesOrderID,
       ProductID,
       OrderQty,
       SUM(OrderQty) OVER win AS [Total],
       AVG(OrderQty) OVER win AS [Avg],
       COUNT(OrderQty) OVER win AS [Count],
       MIN(OrderQty) OVER win AS [Min],
       MAX(OrderQty) OVER win AS [Max]
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664)
WINDOW win AS (PARTITION BY SalesOrderID);

以下查询与上一个查询等效,而不使用 WINDOW 子句。

USE AdventureWorks2025;
GO

SELECT SalesOrderID,
       ProductID,
       OrderQty,
       SUM(OrderQty) OVER (PARTITION BY SalesOrderID) AS [Total],
       AVG(OrderQty) OVER (PARTITION BY SalesOrderID) AS [Avg],
       COUNT(OrderQty) OVER (PARTITION BY SalesOrderID) AS [Count],
       MIN(OrderQty) OVER (PARTITION BY SalesOrderID) AS [Min],
       MAX(OrderQty) OVER (PARTITION BY SalesOrderID) AS [Max]
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664);

结果集如下。

SalesOrderID ProductID OrderQty Total Avg Count Min Max
43659 776 1 26 2 12 1 6
43659 777 3 26 2 12 1 6
43659 778 1 26 2 12 1 6
43659 771 1 26 2 12 1 6
43659 772 1 26 2 12 1 6
43659 773 2 26 2 12 1 6
43659 774 1 26 2 12 1 6
43659 714 3 26 2 12 1 6
43659 716 1 26 2 12 1 6
43659 709 6 26 2 12 1 6
43659 712 2 26 2 12 1 6
43659 711 4 26 2 12 1 6
43664 772 1 14 1 8 1 4
43664 775 4 14 1 8 1 4
43664 714 1 14 1 8 1 4
43664 716 1 14 1 8 1 4
43664 777 2 14 1 8 1 4
43664 771 3 14 1 8 1 4
43664 773 1 14 1 8 1 4
43664 778 1 14 1 8 1 4

C. 在 window 子句中定义通用规范

此示例演示如何在窗口中定义通用规范,并使用它在子句中 OVER 定义其他规范。

ALTER DATABASE AdventureWorks2025
SET COMPATIBILITY_LEVEL = 160;
GO

USE AdventureWorks2025;
GO

SELECT SalesOrderID AS OrderNumber,
       ProductID,
       OrderQty AS Qty,
       SUM(OrderQty) OVER win AS Total,
       AVG(OrderQty) OVER (
           win PARTITION BY SalesOrderID
       ) AS Avg,
       COUNT(OrderQty) OVER (
           win ROWS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING
       ) AS Count
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664)
      AND ProductID LIKE '71%'
WINDOW win AS (
    ORDER BY SalesOrderID, ProductID
);

以下查询与上一个查询等效,而不使用 WINDOW 子句。

USE AdventureWorks2025;
GO

SELECT SalesOrderID AS OrderNumber,
       ProductID,
       OrderQty AS Qty,
       SUM(OrderQty) OVER (
           ORDER BY SalesOrderID, ProductID
       ) AS Total,
       AVG(OrderQty) OVER (
           PARTITION BY SalesOrderID ORDER BY SalesOrderID, ProductID
       ) AS Avg,
       COUNT(OrderQty) OVER (
           ORDER BY SalesOrderID, ProductID ROWS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING
       ) AS Count
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664)
      AND ProductID LIKE '71%';

结果集如下。

OrderNumber ProductID Qty Total Avg Count
43659 711 4 4 4 2
43659 712 2 6 3 3
43659 714 3 9 3 4
43659 716 1 10 2 5
43664 714 1 11 1 6
43664 716 1 12 1 6

D. 向前和向后的窗口引用

此示例演示如何在子句中 WINDOW 定义新窗口时使用命名窗口作为向前和向后引用。

ALTER DATABASE AdventureWorks2025
SET COMPATIBILITY_LEVEL = 160;
GO

USE AdventureWorks2025;
GO

SELECT SalesOrderID AS OrderNumber,
       ProductID,
       OrderQty AS Qty,
       SUM(OrderQty) OVER win2 AS Total,
       AVG(OrderQty) OVER win1 AS Avg
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664)
      AND ProductID LIKE '71%'
WINDOW win1 AS (win3),
       win2 AS (ORDER BY SalesOrderID, ProductID),
       win3 AS (win2 PARTITION BY SalesOrderID);

以下查询与上一个查询等效,而不使用 WINDOW 子句。

USE AdventureWorks2025;
GO

SELECT SalesOrderID AS OrderNumber,
       ProductID,
       OrderQty AS Qty,
       SUM(OrderQty) OVER (
           ORDER BY SalesOrderID, ProductID
       ) AS Total,
       AVG(OrderQty) OVER (
           PARTITION BY SalesOrderID ORDER BY SalesOrderID, ProductID
       ) AS Avg
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN (43659, 43664)
      AND ProductID LIKE '71%';

结果集如下。

OrderNumber ProductID Qty Total Avg
43659 711 4 4 4
43659 712 2 6 3
43659 714 3 9 3
43659 716 1 10 2
43664 714 1 11 1
43664 716 1 12 1