SELECT - OVER 子句 (Transact-SQL)
適用於:SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體 Azure Synapse Analytics Analytics Platform System (PDW) Microsoft Fabric 的 SQL 端點分析 Microsoft Fabric 的倉儲
在套用相關的視窗函數之前,決定資料列集的資料分割和排序。 也就是說,OVER 子句會定義查詢結果集內的視窗或使用者指定的資料列集。 然後視窗函數會針對視窗中的每個資料列來計算值。 您可以搭配函數使用 OVER 子句,以便計算彙總值,例如移動平均值、累計彙總、累加值或是每組前 N 個結果。
語法
-- Syntax for SQL Server, Azure SQL Database, and Azure Synapse Analytics
OVER (
[ <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>
<window frame extent> ::=
{ <window frame preceding>
| <window frame between>
}
<window frame between> ::=
BETWEEN <window frame bound> AND <window frame bound>
<window frame bound> ::=
{ <window frame preceding>
| <window frame following>
}
<window frame preceding> ::=
{
UNBOUNDED PRECEDING
| <unsigned_value_specification> PRECEDING
| CURRENT ROW
}
<window frame following> ::=
{
UNBOUNDED FOLLOWING
| <unsigned_value_specification> FOLLOWING
| CURRENT ROW
}
<unsigned value specification> ::=
{ <unsigned integer literal> }
-- Syntax for Parallel Data Warehouse
OVER ( [ PARTITION BY value_expression ] [ order_by_clause ] )
引數
視窗函數的 OVER
子句中可能有下列引數:
- PARTITION BY 可將查詢結果集分成幾個資料分割。
- ORDER BY 可定義結果集的每個資料分割內資料列的邏輯順序。
- ROWS/RANGE 可透過指定資料分割中的起點和終點來限制資料分割內的資料列。 其需要
ORDER BY
引數,且在指定ORDER BY
引數的情況下,其預設值為資料分割的開頭至目前的元素。
如果您未指定任何引數,則視窗函數會套用到整個結果集。
select
object_id
, [min] = min(object_id) over()
, [max] = max(object_id) over()
from sys.objects
object_id | 分鐘 | max |
---|---|---|
3 | 3 | 2139154666 |
5 | 3 | 2139154666 |
... | ... | ... |
2123154609 | 3 | 2139154666 |
2139154666 | 3 | 2139154666 |
PARTITION BY
將查詢結果集分成幾個資料分割。 視窗函數會分別套用至每個資料分割,並且針對每個資料分割重新開始計算。
PARTITION BY *value_expression*
如未指定 PARTITION BY,則函式會將查詢結果集的所有資料列視為單一資料分割。
如未指定 ORDER BY
子句,則函式會套用至資料分割中的所有資料列。
PARTITION BY value_expression
指定分割資料列集所根據的資料行。 value_expression 只能參考 FROM 子句所提供的資料行。 value_expression 無法參考選取清單中的運算式或別名。 value_expression 可以是資料行運算式、純量子查詢、純量函數或使用者定義的變數。
select
object_id, type
, [min] = min(object_id) over(partition by type)
, [max] = max(object_id) over(partition by type)
from sys.objects
object_id | 類型 | 分鐘 | max |
---|---|---|---|
68195293 | PK | 68195293 | 711673583 |
631673298 | PK | 68195293 | 711673583 |
711673583 | PK | 68195293 | 711673583 |
... | ... | ... | |
3 | S | 3 | 98 |
5 | S | 3 | 98 |
... | ... | ... | |
98 | S | 3 | 98 |
... | ... | ... |
排序依據
ORDER BY *order_by_expression* [COLLATE *collation_name*] [ASC|DESC]
定義結果集的每個資料分割內資料列的邏輯順序。 也就是說,其會指定執行視窗函數計算的邏輯順序。
- 如未指定,則預設的順序為
ASC
,而且視窗函數會使用資料分割中的所有資料列。 - 若已指定,但未指定 ROWS/RANGE,則可接受選用 ROWS/RANGE 規格的函式 (例如
min
或max
) 會使用預設的RANGE UNBOUNDED PRECEDING AND CURRENT ROW
作為視窗框架的預設值。
select
object_id, type
, [min] = min(object_id) over(partition by type order by object_id)
, [max] = max(object_id) over(partition by type order by object_id)
from sys.objects
object_id | 類型 | 分鐘 | max |
---|---|---|---|
68195293 | PK | 68195293 | 68195293 |
631673298 | PK | 68195293 | 631673298 |
711673583 | PK | 68195293 | 711673583 |
... | ... | ... | |
3 | S | 3 | 3 |
5 | S | 3 | 5 |
6 | S | 3 | 6 |
... | ... | ... | |
97 | S | 3 | 97 |
98 | S | 3 | 98 |
... | ... | ... |
order_by_expression
指定排序的資料行或運算式。 order_by_expression 只能參考 FROM 子句所提供的資料行。 不能指定整數來代表資料行名稱或別名。
COLLATE collation_name
指定應該根據 collation_name 中指定的定序來執行 ORDER BY 作業。 collation_name 可以是 Windows 定序名稱或 SQL 定序名稱。 如需詳細資訊,請參閱 Collation and Unicode Support。 COLLATE 只適用於下列類型的資料行:char、varchar、nchar 及 nvarchar。
ASC | DESC
指定指定之資料行的值應該以遞增或遞減順序排序。 ASC 是預設排序次序。 Null 值會當做最低的可能值來處理。
ROWS 或 RANGE
適用於:SQL Server 2012 (11.x) 和更新版本。
指定資料分割內的起始點和結束點,以進一步限制資料分割中的資料列。 這可以藉由指定與目前資料列有關的資料列範圍 (透過邏輯關聯或實體關聯) 來完成。 可以使用 ROWS 子句來達成實體關聯。
ROWS 子句會限制資料分割內的資料列,方法是指定目前資料列之前或之後的固定資料列數。 另外,RANGE 子句會以邏輯方式限制資料分割內的資料列,方法是指定與目前資料列的值相關的值範圍。 前後的資料列是根據 ORDER BY 子句的順序定義。 視窗框架 "RANGE ...CURRENT ROW ..." 包含 ORDER BY 運算式中,與目前資料列相同值的所有資料列。 例如,ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 表示此函數操作所在的資料列視窗大小為三個資料列,從之前的 2 個資料列直到目前的資料列。
select
object_id
, [preceding] = count(*) over(order by object_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW )
, [central] = count(*) over(order by object_id ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING )
, [following] = count(*) over(order by object_id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
from sys.objects
order by object_id asc
object_id | preceding | central | following |
---|---|---|---|
3 | 1 | 3 | 156 |
5 | 2 | 4 | 155 |
6 | 3 | 5 | 154 |
7 | 4 | 5 | 153 |
8 | 5 | 5 | 152 |
... | ... | ... | ... |
2112726579 | 153 | 5 | 4 |
2119678599 | 154 | 5 | 3 |
2123154609 | 155 | 4 | 2 |
2139154666 | 156 | 3 | 1 |
注意
ROWS 或 RANGE 要求必須指定 ORDER BY 子句。 如果 ORDER BY 包含多個順序運算式,則 CURRENT ROW FOR RANGE 會在判斷目前資料列時,考量 ORDER BY 清單中的所有資料列。
UNBOUNDED PRECEDING
適用於:SQL Server 2012 (11.x) 和更新版本。
指定視窗從資料分割的第一個資料列開始。 只能將 UNBOUNDED PRECEDING 指定為視窗起點。
<不帶正負號值規格> PRECEDING
與 <不帶正負號值規格> 一起指定,可指出要置於目前資料列前面的資料列或值數目。 RANGE 不允許這項指定。
CURRENT ROW
適用於:SQL Server 2012 (11.x) 和更新版本。
指定在與 ROWS 一起使用時,視窗在目前的資料列開始或結束,或者在與 RANGE 一起使用時則為目前值。 CURRENT ROW 可以指定為開始點和結束點。
BETWEEN AND
適用於:SQL Server 2012 (11.x) 和更新版本。
BETWEEN <window frame bound > AND <window frame bound >
與 ROWS 或 RANGE 一起使用,以指定視窗的下 (開始) 邊界點和上 (結束) 邊界點。 <視窗框架界限> 定義界限起點,而 <視窗框架界限> 則定義界限終點。 上限不能小於下限。
UNBOUNDED FOLLOWING
適用於:SQL Server 2012 (11.x) 和更新版本。
指定視窗在資料分割的最後一個資料列結束。 只能將 UNBOUNDED FOLLOWING 指定為視窗結束點。 例如,RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 會定義一個視窗,此視窗從資料分割的目前資料列開始,並結束於資料分割的最後一個資料列。
<不帶正負號值規格> FOLLOWING
與 <不帶正負號值規格> 一起指定,可指出要置於目前資料列後面的資料列或值數目。 將 <不帶正負號值規格> FOLLOWING 指定為視窗起點時,終點必須是 <不帶正負號值規格> FOLLOWING。 例如,ROWS BETWEEN 2 FOLLOWING AND 10 FOLLOWING 會定義一個視窗,此視窗從目前資料列後面的第二個資料列開始,並結束於目前資料列後面的第十個資料列。 RANGE 不允許這項指定。
不帶正負號的整數常值
適用於:SQL Server 2012 (11.x) 和更新版本。
一個正整數常值 (包括 0),可指定要置於目前資料列或值前面或後面的資料列或值的數目。 這項指定只對 ROWS 有效。
備註
在含有一個 FROM 子句的單一查詢中,可以使用一個以上的視窗函數。 每個函數的 OVER 子句在進行資料分割和進行排序時,都不一樣。
如未指定 PARTITION BY,此函數會將查詢結果集的所有資料列視為單一群組。
重要
如果指定了 ROWS/RANGE,且 <window frame preceding>
用於 <window frame extent>
(簡短語法),則這個指定會用於視窗框架界限開始點,而 CURRENT ROW 則用於界限結束點。 例如,"ROWS 5 PRECEDING" 等於 "ROWS BETWEEN 5 PRECEDING AND CURRENT ROW"。
注意
如果未指定 ORDER BY,則將整個資料分割用於視窗框架。 這只適用於不需要 ORDER BY 子句的函數。 如果未指定 ROWS/RANGE,但指定了 ORDER BY,則將 RANGE UNBOUNDED PRECEDING AND CURRENT ROW 當做視窗框架的預設值。 這只適用於可以接受選擇性 ROWS/RANGE 指定的函數。 例如,排名函數不能接受 ROWS/RANGE,因此,即使存在 ORDER BY 而不存在 ROWS/RANGE,這個視窗框架依然不適用。
限制事項
OVER 子句不能與 DISTINCT 匯總搭配使用。
RANGE 不能搭配 <不帶正負號值規格> PRECEDING 或 <不帶正負號值規格> FOLLOWING 使用。
根據與 OVER 子句搭配使用的順位、彙總或分析函式,可能不支援 <ORDER BY 子句> 及/或 <ROWS 和 RANGE 子句>。
範例
A. 搭配 ROW_NUMBER 函數來使用 OVER 子句
下列範例示範如何搭配 ROW_NUMBER 函數使用 OVER 子句,以針對資料分割內的每一個資料列顯示資料列號碼。 OVER 子句中指定的 ORDER BY 子句會依照 SalesYTD
資料行來排序每一個資料分割中的資料列。 SELECT 陳述式中的 ORDER BY 子句會決定傳回整個查詢結果集的順序。
USE AdventureWorks2022;
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;
GO
以下為結果集。
Row Number 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 Varkey Chudukatil 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
子句。 在這個範例中,使用 OVER
子句比使用子查詢來衍生彙總值更有效率。
USE AdventureWorks2022;
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);
GO
以下為結果集。
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
下列範例顯示在計算值中搭配彙總函式來使用 OVER
子句。
USE AdventureWorks2022;
GO
SELECT SalesOrderID, ProductID, OrderQty
,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS Total
,CAST(1. * OrderQty / SUM(OrderQty) OVER(PARTITION BY SalesOrderID)
*100 AS DECIMAL(5,2))AS "Percent by ProductID"
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN(43659,43664);
GO
以下為結果集。 請注意,彙總是以 SalesOrderID
來計算,而且每個 Percent by ProductID
的每一行都會計算出 SalesOrderID
。
SalesOrderID ProductID OrderQty Total Percent by ProductID
------------ ----------- -------- ----------- ---------------------------------------
43659 776 1 26 3.85
43659 777 3 26 11.54
43659 778 1 26 3.85
43659 771 1 26 3.85
43659 772 1 26 3.85
43659 773 2 26 7.69
43659 774 1 26 3.85
43659 714 3 26 11.54
43659 716 1 26 3.85
43659 709 6 26 23.08
43659 712 2 26 7.69
43659 711 4 26 15.38
43664 772 1 14 7.14
43664 775 4 14 28.57
43664 714 1 14 7.14
43664 716 1 14 7.14
43664 777 2 14 14.29
43664 771 3 14 21.4
43664 773 1 14 7.14
43664 778 1 14 7.14
(20 row(s) affected)
C. 產生移動平均值和累計總和
下列範例搭配 OVER 子句來使用 AVG 與 SUM 函數,為 Sales.SalesPerson
資料表中各領域的年度銷售提供移動平均值和累計總和。 TerritoryID
負責分割資料,而 SalesYTD
會進行邏輯性地排序。 這表示,將會根據銷售年度來針對每一個領域計算 AVG 函數。 請注意,在 TerritoryID
1 中,2005 銷售年度有兩個資料列,分別表示在該年度有銷售業績的兩個銷售人員。 計算這兩個資料列的平均銷售額,然後將表示 2006 年度銷售額的第三個資料列納入計算。
USE AdventureWorks2022;
GO
SELECT BusinessEntityID, TerritoryID
,DATEPART(yy,ModifiedDate) AS SalesYear
,CONVERT(VARCHAR(20),SalesYTD,1) AS SalesYTD
,CONVERT(VARCHAR(20),AVG(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
),1) AS MovingAvg
,CONVERT(VARCHAR(20),SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
),1) AS CumulativeTotal
FROM Sales.SalesPerson
WHERE TerritoryID IS NULL OR TerritoryID < 5
ORDER BY TerritoryID,SalesYear;
以下為結果集。
BusinessEntityID TerritoryID SalesYear SalesYTD MovingAvg CumulativeTotal
---------------- ----------- ----------- -------------------- -------------------- --------------------
274 NULL 2005 559,697.56 559,697.56 559,697.56
287 NULL 2006 519,905.93 539,801.75 1,079,603.50
285 NULL 2007 172,524.45 417,375.98 1,252,127.95
283 1 2005 1,573,012.94 1,462,795.04 2,925,590.07
280 1 2005 1,352,577.13 1,462,795.04 2,925,590.07
284 1 2006 1,576,562.20 1,500,717.42 4,502,152.27
275 2 2005 3,763,178.18 3,763,178.18 3,763,178.18
277 3 2005 3,189,418.37 3,189,418.37 3,189,418.37
276 4 2005 4,251,368.55 3,354,952.08 6,709,904.17
281 4 2005 2,458,535.62 3,354,952.08 6,709,904.17
(10 row(s) affected)
在這個範例中,OVER 子句未包含 PARTITION BY。 這表示,該函數將套用到查詢所傳回的所有資料列。 OVER 子句中指定的 ORDER BY 子句會決定套用 AVG 函數的邏輯順序。 此查詢會依照 WHERE 子句中指定的所有銷售領域傳回依年度的銷售量移動平均值。 SELECT 陳述式中指定的 ORDER BY 子句會決定查詢的資料列顯示的順序。
SELECT BusinessEntityID, TerritoryID
,DATEPART(yy,ModifiedDate) AS SalesYear
,CONVERT(VARCHAR(20),SalesYTD,1) AS SalesYTD
,CONVERT(VARCHAR(20),AVG(SalesYTD) OVER (ORDER BY DATEPART(yy,ModifiedDate)
),1) AS MovingAvg
,CONVERT(VARCHAR(20),SUM(SalesYTD) OVER (ORDER BY DATEPART(yy,ModifiedDate)
),1) AS CumulativeTotal
FROM Sales.SalesPerson
WHERE TerritoryID IS NULL OR TerritoryID < 5
ORDER BY SalesYear;
以下為結果集。
BusinessEntityID TerritoryID SalesYear SalesYTD MovingAvg CumulativeTotal
---------------- ----------- ----------- -------------------- -------------------- --------------------
274 NULL 2005 559,697.56 2,449,684.05 17,147,788.35
275 2 2005 3,763,178.18 2,449,684.05 17,147,788.35
276 4 2005 4,251,368.55 2,449,684.05 17,147,788.35
277 3 2005 3,189,418.37 2,449,684.05 17,147,788.35
280 1 2005 1,352,577.13 2,449,684.05 17,147,788.35
281 4 2005 2,458,535.62 2,449,684.05 17,147,788.35
283 1 2005 1,573,012.94 2,449,684.05 17,147,788.35
284 1 2006 1,576,562.20 2,138,250.72 19,244,256.47
287 NULL 2006 519,905.93 2,138,250.72 19,244,256.47
285 NULL 2007 172,524.45 1,941,678.09 19,416,780.93
(10 row(s) affected)
D. 指定 ROWS 子句
適用於:SQL Server 2012 (11.x) 和更新版本。
下列範例會使用 ROWS 子句來定義一個視窗,其上的資料列會計算為目前資料列與隨後的 N 個資料列 (在此範例中為 1 個資料列)。
SELECT BusinessEntityID, TerritoryID
,CONVERT(VARCHAR(20),SalesYTD,1) AS SalesYTD
,DATEPART(yy,ModifiedDate) AS SalesYear
,CONVERT(VARCHAR(20),SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING ),1) AS CumulativeTotal
FROM Sales.SalesPerson
WHERE TerritoryID IS NULL OR TerritoryID < 5;
以下為結果集。
BusinessEntityID TerritoryID SalesYTD SalesYear CumulativeTotal
---------------- ----------- -------------------- ----------- --------------------
274 NULL 559,697.56 2005 1,079,603.50
287 NULL 519,905.93 2006 692,430.38
285 NULL 172,524.45 2007 172,524.45
283 1 1,573,012.94 2005 2,925,590.07
280 1 1,352,577.13 2005 2,929,139.33
284 1 1,576,562.20 2006 1,576,562.20
275 2 3,763,178.18 2005 3,763,178.18
277 3 3,189,418.37 2005 3,189,418.37
276 4 4,251,368.55 2005 6,709,904.17
281 4 2,458,535.62 2005 2,458,535.62
在下列範例中,會使用 UNBOUNDED PRECEDING 來指定 ROWS 子句。 結果是視窗從資料分割的第一個資料列開始。
SELECT BusinessEntityID, TerritoryID
,CONVERT(VARCHAR(20),SalesYTD,1) AS SalesYTD
,DATEPART(yy,ModifiedDate) AS SalesYear
,CONVERT(VARCHAR(20),SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
ROWS UNBOUNDED PRECEDING),1) AS CumulativeTotal
FROM Sales.SalesPerson
WHERE TerritoryID IS NULL OR TerritoryID < 5;
以下為結果集。
BusinessEntityID TerritoryID SalesYTD SalesYear CumulativeTotal
---------------- ----------- -------------------- ----------- --------------------
274 NULL 559,697.56 2005 559,697.56
287 NULL 519,905.93 2006 1,079,603.50
285 NULL 172,524.45 2007 1,252,127.95
283 1 1,573,012.94 2005 1,573,012.94
280 1 1,352,577.13 2005 2,925,590.07
284 1 1,576,562.20 2006 4,502,152.27
275 2 3,763,178.18 2005 3,763,178.18
277 3 3,189,418.37 2005 3,189,418.37
276 4 4,251,368.55 2005 4,251,368.55
281 4 2,458,535.62 2005 6,709,904.17
範例:Analytics Platform System (PDW)
E. 搭配 ROW_NUMBER 函數來使用 OVER 子句
下列範例會根據指派給業務代表的銷售配額,傳回業務代表的 ROW_NUMBER。
-- Uses AdventureWorks
SELECT ROW_NUMBER() OVER(ORDER BY SUM(SalesAmountQuota) DESC) AS RowNumber,
FirstName, LastName,
CONVERT(VARCHAR(13), SUM(SalesAmountQuota),1) AS SalesQuota
FROM dbo.DimEmployee AS e
INNER JOIN dbo.FactSalesQuota AS sq
ON e.EmployeeKey = sq.EmployeeKey
WHERE e.SalesPersonFlag = 1
GROUP BY LastName, FirstName;
以下為部分結果集。
RowNumber FirstName LastName SalesQuota
--------- --------- ------------------ -------------
1 Jillian Carson 12,198,000.00
2 Linda Mitchell 11,786,000.00
3 Michael Blythe 11,162,000.00
4 Jae Pak 10,514,000.00
F. 搭配彙總函式來使用 OVER 子句
下列範例示範如何搭配彙總函數使用 OVER 子句。 在這個範例中,使用 OVER 子句比使用子查詢更有效率。
-- Uses AdventureWorks
SELECT SalesOrderNumber AS OrderNumber, ProductKey,
OrderQuantity AS Qty,
SUM(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Total,
AVG(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Avg,
COUNT(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Count,
MIN(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Min,
MAX(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Max
FROM dbo.FactResellerSales
WHERE SalesOrderNumber IN(N'SO43659',N'SO43664') AND
ProductKey LIKE '2%'
ORDER BY SalesOrderNumber,ProductKey;
以下為結果集。
OrderNumber Product Qty Total Avg Count Min Max
----------- ------- --- ----- --- ----- --- ---
SO43659 218 6 16 3 5 1 6
SO43659 220 4 16 3 5 1 6
SO43659 223 2 16 3 5 1 6
SO43659 229 3 16 3 5 1 6
SO43659 235 1 16 3 5 1 6
SO43664 229 1 2 1 2 1 1
SO43664 235 1 2 1 2 1 1
下列範例示範如何在計算值中搭配彙總函數使用 OVER 子句。 請注意,會依 SalesOrderNumber
計算彙總,並且會為每個 SalesOrderNumber
的每一行計算出銷售訂單總計百分比。
-- Uses AdventureWorksDW2022
SELECT SalesOrderNumber AS OrderNumber, ProductKey AS Product,
OrderQuantity AS Qty,
SUM(OrderQuantity) OVER(PARTITION BY SalesOrderNumber) AS Total,
CAST(1. * OrderQuantity / SUM(OrderQuantity)
OVER(PARTITION BY SalesOrderNumber)
*100 AS DECIMAL(5,2)) AS PctByProduct
FROM dbo.FactResellerSales
WHERE SalesOrderNumber IN(N'SO43659',N'SO43664') AND
ProductKey LIKE '2%'
ORDER BY SalesOrderNumber,ProductKey;
此結果集的第一個開始為:
OrderNumber Product Qty Total PctByProduct
----------- ------- --- ----- ------------
SO43659 218 6 16 37.50
SO43659 220 4 16 25.00
SO43659 223 2 16 12.50
SO43659 229 2 16 18.75
另請參閱
彙總函式 (Transact-SQL)
分析函數 (Transact-SQL)
Itzik Ben-Gan 在 sqlmag.com 上所發表有關視窗函數和 OVER 的精彩部落格文章 \(英文\)