TOP (Transact-SQL)
適用於:MICROSOFT網狀架構 Microsoft倉儲中的 SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體 Azure Synapse Analytics Analytics Platform System (PDW)SQL 分析端點Microsoft網狀架構
在 SQL Server 中,將查詢結果集中傳回的資料列數限制為指定的資料列數或資料列數的百分比。 當您搭配 ORDER BY
子句使用 TOP
時,結果集會限制為第一個 n 個已排序的數據列數目。 否則,TOP
會以未定義的順序傳回第一個 n 個 個數據列數目。 使用這個子句來指定從 SELECT
語句傳回的數據列數目。 或者,使用 TOP
來指定受 INSERT
、UPDATE
、MERGE
或 DELETE
語句影響的數據列。
語法
SQL Server 和 Azure SQL Database 的語法:
[
TOP (expression) [ PERCENT ]
[ WITH TIES ]
]
Azure Synapse Analytics 和分析平台系統的語法(PDW):
[
TOP ( expression )
[ WITH TIES ]
]
引數
expression
指定所要傳回資料列數目的數值運算式。 如果您指定 PERCENT
,表示式 會隱含轉換成 float 值。 否則,expression 會轉換為 bigint。
PERCENT
指出查詢只從結果集中傳回前 expression % 的資料列。 含小數的值會無條件進位到下一個整數值。
WITH TIES
傳回針對限制結果集中的最後一個位數繫結的兩個或多個資料列。 您必須將此自變數與 ORDER BY
子句搭配使用。
WITH TIES
可能會導致傳回的數據列數目比 表示式中指定的值。 例如,如果 表示式 設定為 5
但另外兩個數據列符合數據列 5 中 ORDER BY
數據行的值,則結果集會包含七個數據列。
您只能在 SELECT
語句中使用 WITH TIES
自變數來指定 TOP
子句,而且只有在您也指定 ORDER BY
子句時。 有同值記錄的傳回順序是任意的。
ORDER BY
不會影響此規則。
最佳做法
在 SELECT
語句中,一律使用 ORDER BY
子句搭配 TOP
子句。 這是可預測指出哪些數據列受到 TOP
影響的唯一方式。
在 ORDER BY
子句中使用 OFFSET
和 FETCH
,而不是使用 TOP
子句來實作查詢分頁解決方案。 分頁解決方案(也就是將數據 的區塊或
使用 TOP
(或 OFFSET
和 FETCH
),而不是 SET ROWCOUNT
來限制傳回的數據列數目。 基於下列原因,建議使用 SET ROWCOUNT
方法:
- 在
SELECT
語句中,查詢優化器可以在查詢優化期間考慮TOP
或FETCH
子句中 表達式 的值。 因為您在執行查詢的語句外部使用SET ROWCOUNT
,因此無法在查詢計劃中考慮其值。
相容性支援
為了保持回溯相容性,如果表達式是整數常數,則括弧在 SELECT
語句中是選擇性的。 建議您一律在 SELECT
語句中使用括弧進行 TOP
。 這樣做可提供 INSERT
、UPDATE
、MERGE
和 DELETE
語句中所需使用的一致性。
互通性
TOP
表示式不會影響可能因為觸發程式而執行的語句。 觸發程式中的 inserted
和 deleted
數據表只會傳回真正受 INSERT
、UPDATE
、MERGE
或 DELETE
語句影響的數據列。 例如,如果 INSERT TRIGGER
引發,則為使用 TOP
子句的 INSERT
語句結果。
SQL Server 允許透過檢視更新資料列。 因為您可以在檢視定義中包含 TOP
子句,所以如果數據列因為更新而不再符合 TOP
表示式的需求,某些數據列可能會從檢視中消失。
在 TOP
子句會進一步將聯結的數據列數目縮減為指定的值,而插入、更新或刪除動作會以未排序的方式套用至其餘聯結的數據列。 也就是說,數據列在 WHEN
子句中定義的動作之間沒有散發的順序。 例如,如果指定 TOP (10)
會影響 10 個數據列,可能會更新其中 7 個數據列,並插入 3 個數據列。 或者,可能會刪除一個、五個更新和四個插入等等。 由於 MERGE
語句會同時執行來源和目標數據表的完整數據表掃描,因此當您使用 TOP
子句來修改大型數據表時,I/O 效能可能會受到影響,方法是建立多個批次。 在此狀況中,請務必確保所有後續批次都以新的資料列為目標。
當您在包含 UNION
、UNION ALL
、EXCEPT
或 INTERSECT
運算子的查詢中指定 TOP
子句時,請小心。 您可以撰寫會傳回非預期結果的查詢,因為當這些運算符用於選取作業時,邏輯上處理 TOP
和 ORDER BY
子句的順序並不一定是直覺的。 例如,提供下列資料表和資料時,假設您想要傳回最便宜的紅色汽車和最便宜的藍色汽車。 也就是紅色轎車和藍色小貨車。
CREATE TABLE dbo.Cars
(
Model VARCHAR (15),
Price MONEY,
Color VARCHAR (10)
);
INSERT dbo.Cars
VALUES ('sedan', 10000, 'red'),
('convertible', 15000, 'blue'),
('coupe', 20000, 'red'),
('van', 8000, 'blue');
若要達成這些結果,您可能撰寫下列查詢。
SELECT TOP (1) Model, Color, Price
FROM dbo.Cars
WHERE Color = 'red'
UNION ALL
SELECT TOP (1) Model, Color, Price
FROM dbo.Cars
WHERE Color = 'blue'
ORDER BY Price ASC;
GO
以下是結果集。
Model Color Price
------------- ---------- -------
sedan red 10000.00
convertible blue 15000.00
傳回非預期的結果,因為 TOP
子句會在 ORDER BY
子句之前邏輯執行,這會排序運算符的結果(在此案例中為UNION ALL
)。 因此,上一個查詢會傳回任何一輛紅色汽車和任何一輛藍色汽車,然後依價格來排序該聯集的結果。 下列範例會顯示為了達到所要的結果,正確撰寫查詢的方法。
SELECT Model, Color, Price
FROM (SELECT TOP (1) Model, Color, Price
FROM dbo.Cars
WHERE Color = 'red'
ORDER BY Price ASC) AS a
UNION ALL
SELECT Model, Color, Price
FROM (SELECT TOP (1) Model, Color, Price
FROM dbo.Cars
WHERE Color = 'blue'
ORDER BY Price ASC) AS b;
GO
藉由在子選取作業中使用 TOP
和 ORDER BY
,您可確保 ORDER BY
子句的結果會套用至 TOP
子句,而不是排序 UNION
作業的結果。
以下是結果集。
Model Color Price
------------- ---------- -------
sedan red 10000.00
van blue 8000.00
局限性
當您搭配 INSERT
、UPDATE
、MERGE
或 DELETE
使用 TOP
時,參考的數據列不會依任何順序排列。 而且,您無法在這些語句中直接指定 ORDER BY
子句。 如果您需要使用 TOP
,以有意義的時間順序插入、刪除或修改數據列,請使用 TOP
搭配子選擇語句中指定的 ORDER BY
子句。 請參閱本文中的 範例 一節。
您無法在資料分割檢視的 UPDATE
或 DELETE
語句中使用 TOP
。
您無法將 TOP
與相同查詢表達式中的 OFFSET
和 FETCH
合併(在同一個查詢範圍中)。 如需詳細資訊,請參閱 SELECT - ORDER BY 子句。
範例
本文中的 Transact-SQL 程式代碼範例會使用 AdventureWorks2022
或 AdventureWorksDW2022
範例資料庫,您可以從 Microsoft SQL Server 範例和社群專案 首頁下載。
類別 | 代表性語法元素 |
---|---|
基本語法 | TOP * PERCENT |
包括相同值 | WITH TIES |
限制受 DELETE、INSERT 或 UPDATE 影響的資料列 |
DELETE 、INSERT 、UPDATE |
基本語法
本節中的範例示範 ORDER BY
子句使用最低必要語法的基本功能。
A. 搭配常數值使用 TOP
下列範例使用常數值,來指定查詢結果集內傳回的員工人數。 在第一個範例中,會傳回前 10 個未定義的數據列,因為未使用 ORDER BY
子句。 在第二個範例中,會使用 ORDER BY
子句傳回最近僱用的員工前 10 名。
USE AdventureWorks2022;
GO
-- Select the first 10 random employees.
SELECT TOP (10) JobTitle, HireDate
FROM HumanResources.Employee;
GO
-- Select the first 10 employees hired most recently.
SELECT TOP (10) JobTitle, HireDate
FROM HumanResources.Employee
ORDER BY HireDate DESC;
GO
B. 搭配變數使用 TOP
下列範例使用變數,來指定查詢結果集內傳回的員工人數。
USE AdventureWorks2022;
GO
DECLARE @p AS INT = 10;
SELECT TOP (@p) JobTitle, HireDate, VacationHours
FROM HumanResources.Employee
ORDER BY VacationHours DESC;
GO
C. 指定百分比
下列範例會使用 PERCENT
來指定查詢結果集中傳回的員工數目。
HumanResources.Employee
資料表有 290 名員工。 因為 290 的 5% 是含小數的值,所以此值會無條件進位到下一個整數。
USE AdventureWorks2022;
GO
SELECT TOP (5) PERCENT JobTitle, HireDate
FROM HumanResources.Employee
ORDER BY HireDate DESC;
GO
包含系結值
A. 使用WITH TIES來包含符合最後一個數據列中值的數據列
下列範例會取得所有員工中薪資最高的 10
%,並依照薪資的遞減順序傳回。 指定 WITH TIES
可確保任何薪資是所傳回之最低薪資 (最後一個資料列) 的員工也會包含在結果集中,即使這樣會超出員工的 10
%,也是如此。
USE AdventureWorks2022;
GO
SELECT TOP (10) PERCENT WITH TIES pp.FirstName,
pp.LastName,
e.JobTitle,
e.Gender,
r.Rate
FROM Person.Person AS pp
INNER JOIN HumanResources.Employee AS e
ON pp.BusinessEntityID = e.BusinessEntityID
INNER JOIN HumanResources.EmployeePayHistory AS r
ON r.BusinessEntityID = e.BusinessEntityID
ORDER BY Rate DESC;
GO
限制受 DELETE、INSERT 或 UPDATE 影響的數據列
A. 使用 TOP 來限制已刪除的數據列數目
當您搭配 DELETE
使用 TOP (<n>)
子句時,刪除作業會在未定義的 n 個 個數據列數目上完成。 也就是說,DELETE
語句會選擇符合 WHERE
子句中所定義準則的任何數據列數目(n)。 下列範例會從 20
資料表刪除到期日早於 2002 年 7 月 1 日的 PurchaseOrderDetail
個資料列。
USE AdventureWorks2022;
GO
DELETE TOP (20)
FROM Purchasing.PurchaseOrderDetail
WHERE DueDate < '20020701';
GO
如果您想要使用 TOP
以有意義的時間順序刪除數據列,請在子選取語句中使用 TOP
搭配 ORDER BY
。 下列查詢會刪除 PurchaseOrderDetail
資料表中具有最早到期日的 10 個資料列。 為確保只刪除 10 個資料列,subselect 陳述式 (PurchaseOrderID
) 中指定的資料行是資料表的主索引鍵。 如果指定的數據行包含重複的值,在子選取語句中使用非索引鍵數據行可能會導致刪除超過10個數據列。
USE AdventureWorks2022;
GO
DELETE Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetailID IN (
SELECT TOP 10 PurchaseOrderDetailID
FROM Purchasing.PurchaseOrderDetail
ORDER BY DueDate ASC
);
GO
B. 使用 TOP 來限制插入的數據列數目
下列範例會建立 EmployeeSales
資料表,且會將 HumanResources.Employee
資料表的前五名員工的姓名和今初至今的銷售資料插入其中。
INSERT
語句會選擇 SELECT
語句傳回的任何五個數據列,以符合 WHERE
子句中定義的準則。
OUTPUT
子句會顯示插入至 EmployeeSales
數據表的數據列。
SELECT
語句中的 ORDER BY
子句不會用來判斷前五名員工。
USE AdventureWorks2022;
GO
IF OBJECT_ID('dbo.EmployeeSales', 'U') IS NOT NULL
DROP TABLE dbo.EmployeeSales;
GO
CREATE TABLE dbo.EmployeeSales
(
EmployeeID NVARCHAR (11) NOT NULL,
LastName NVARCHAR (20) NOT NULL,
FirstName NVARCHAR (20) NOT NULL,
YearlySales MONEY NOT NULL
);
GO
INSERT TOP (5) INTO dbo.EmployeeSales
OUTPUT
inserted.EmployeeID,
inserted.FirstName,
inserted.LastName,
inserted.YearlySales
SELECT sp.BusinessEntityID,
c.LastName,
c.FirstName,
sp.SalesYTD
FROM Sales.SalesPerson AS sp
INNER JOIN Person.Person AS c
ON sp.BusinessEntityID = c.BusinessEntityID
WHERE sp.SalesYTD > 250000.00
ORDER BY sp.SalesYTD DESC;
GO
如果您想要使用 TOP
,以有意義的時間順序插入數據列,請在子選擇語句中使用 TOP
搭配 ORDER BY
。 下列範例示範如何執行這項操作。
OUTPUT
子句會顯示插入至 EmployeeSales
數據表的數據列。 前五名員工現在會根據 ORDER BY
子句的結果來插入,而不是未定義的數據列。
INSERT INTO dbo.EmployeeSales
OUTPUT
inserted.EmployeeID,
inserted.FirstName,
inserted.LastName,
inserted.YearlySales
SELECT TOP (5) sp.BusinessEntityID,
c.LastName,
c.FirstName,
sp.SalesYTD
FROM Sales.SalesPerson AS sp
INNER JOIN Person.Person AS c
ON sp.BusinessEntityID = c.BusinessEntityID
WHERE sp.SalesYTD > 250000.00
ORDER BY sp.SalesYTD DESC;
GO
C. 使用 TOP 來限制更新的數據列數目
下列範例會使用 TOP
子句來更新數據表中的數據列。 當您搭配 UPDATE
使用 TOP (<n>)
子句時,更新作業會在未定義的數據列數目上執行。 也就是說,UPDATE
語句會選擇符合 WHERE
子句中所定義準則的任何數據列數目(n)。 下列範例會從某位銷售人員指派 10 位客戶給另一位銷售人員。
USE AdventureWorks2022;
UPDATE TOP (10)
Sales.Store
SET SalesPersonID = 276
WHERE SalesPersonID = 275;
GO
如果您必須使用 TOP
在有意義的時序中套用更新,則必須在子選取語句中使用 TOP
搭配 ORDER BY
。 下例會更新最早雇用的前 10 名員工的休假時數。
UPDATE HumanResources.Employee
SET VacationHours = VacationHours + 8
FROM (SELECT TOP 10 BusinessEntityID
FROM HumanResources.Employee
ORDER BY HireDate ASC) AS th
WHERE HumanResources.Employee.BusinessEntityID = th.BusinessEntityID;
GO
範例:Azure Synapse Analytics 和 Analytics Platform System (PDW)
下列範例會傳回符合查詢準則的前 31 個資料列。
ORDER BY
子句可確保 31 個傳回的數據列是以 LastName
數據行的字母順序為基礎的前 31 個數據列。
使用 TOP
而不指定系結。
SELECT TOP (31) FirstName, LastName
FROM DimEmployee
ORDER BY LastName;
結果:傳回 31 個資料列。
使用 TOP
,指定 WITH TIES
。
SELECT TOP (31) WITH TIES FirstName, LastName
FROM DimEmployee
ORDER BY LastName;
結果:傳回 33 個數據列,因為名為 Brown
第 31 個數據列的三位員工系結。