SELECT - WINDOW 子句 (Transact-SQL)

適用於: SQL Server 2022 (16.x) 及後版本 Azure SQL Database AzureSQL Managed InstanceMicrosoft Fabric 中的 SQL 資料庫

子句中的 WINDOW 具名視窗定義會決定數據列集在 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 必須在參考視窗的視窗定義中指定。 一個視窗中定義的視窗元件無法由另一個參考它的視窗重新定義。

根據時間範圍定義於時間範圍子句中的順序,會允許前向和後向時間範圍參考。 換句話說,視窗可能會使用在視窗表達式中定義的任何其他視窗,做為 reference_window_name,而不論其定義順序為何。 不允許在單一視窗中循環參考和使用多個窗口參考。

包含在視窗表達式中之已定義視窗的新 window_name 範圍,包含任何屬於窗口表示式一部分的窗口定義,以及 SELECT 包含 window 子句的查詢規格或 SELECT 語句的 子句。 如果窗口表達式包含在屬於查詢表達式的查詢規格中,這是基本數據表查詢,則新 window_name 的範圍也會包含 ORDER BY 該查詢表達式的表達式。如果有任何的話,該查詢表達式的範圍。

子句中 OVER 具有匯總和分析函式之窗口規格使用限制,其語意適用於 WINDOW 子句。

Examples

本文的程式碼範例使用AdventureWorks2025了 、 AdventureWorksDW2025或AdventureWorksLT2025範例資料庫,你可以從 Azure Data SQL 範例庫 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