共用方式為


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 來指定受 INSERTUPDATEMERGEDELETE 語句影響的數據列。

Transact-SQL 語法慣例

語法

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 子句中使用 OFFSETFETCH,而不是使用 TOP 子句來實作查詢分頁解決方案。 分頁解決方案(也就是將數據 的區塊或 頁面傳送至用戶端)更容易使用 子句來實作。 如需詳細資訊,請參閱 SELECT - ORDER BY 子句

使用 TOP (或 OFFSETFETCH),而不是 SET ROWCOUNT 來限制傳回的數據列數目。 基於下列原因,建議使用 SET ROWCOUNT 方法:

  • SELECT 語句中,查詢優化器可以在查詢優化期間考慮 TOPFETCH 子句中 表達式 的值。 因為您在執行查詢的語句外部使用 SET ROWCOUNT,因此無法在查詢計劃中考慮其值。

相容性支援

為了保持回溯相容性,如果表達式是整數常數,則括弧在 SELECT 語句中是選擇性的。 建議您一律在 SELECT 語句中使用括弧進行 TOP。 這樣做可提供 INSERTUPDATEMERGEDELETE 語句中所需使用的一致性。

互通性

TOP 表示式不會影響可能因為觸發程式而執行的語句。 觸發程式中的 inserteddeleted 數據表只會傳回真正受 INSERTUPDATEMERGEDELETE 語句影響的數據列。 例如,如果 INSERT TRIGGER 引發,則為使用 TOP 子句的 INSERT 語句結果。

SQL Server 允許透過檢視更新資料列。 因為您可以在檢視定義中包含 TOP 子句,所以如果數據列因為更新而不再符合 TOP 表示式的需求,某些數據列可能會從檢視中消失。

語句中指定時, 子句會在 整個源數據表和整個目標數據表聯結之後套用 。 並且,將會移除不符合插入、更新或刪除動作的聯結資料列。 TOP 子句會進一步將聯結的數據列數目縮減為指定的值,而插入、更新或刪除動作會以未排序的方式套用至其餘聯結的數據列。 也就是說,數據列在 WHEN 子句中定義的動作之間沒有散發的順序。 例如,如果指定 TOP (10) 會影響 10 個數據列,可能會更新其中 7 個數據列,並插入 3 個數據列。 或者,可能會刪除一個、五個更新和四個插入等等。 由於 MERGE 語句會同時執行來源和目標數據表的完整數據表掃描,因此當您使用 TOP 子句來修改大型數據表時,I/O 效能可能會受到影響,方法是建立多個批次。 在此狀況中,請務必確保所有後續批次都以新的資料列為目標。

當您在包含 UNIONUNION ALLEXCEPTINTERSECT 運算子的查詢中指定 TOP 子句時,請小心。 您可以撰寫會傳回非預期結果的查詢,因為當這些運算符用於選取作業時,邏輯上處理 TOPORDER 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

藉由在子選取作業中使用 TOPORDER BY,您可確保 ORDER BY 子句的結果會套用至 TOP 子句,而不是排序 UNION 作業的結果。

以下是結果集。

 Model         Color      Price
 ------------- ---------- -------
 sedan         red        10000.00
 van           blue        8000.00

局限性

當您搭配 INSERTUPDATEMERGEDELETE使用 TOP 時,參考的數據列不會依任何順序排列。 而且,您無法在這些語句中直接指定 ORDER BY 子句。 如果您需要使用 TOP,以有意義的時間順序插入、刪除或修改數據列,請使用 TOP 搭配子選擇語句中指定的 ORDER BY 子句。 請參閱本文中的 範例 一節。

您無法在資料分割檢視的 UPDATEDELETE 語句中使用 TOP

您無法將 TOP 與相同查詢表達式中的 OFFSETFETCH 合併(在同一個查詢範圍中)。 如需詳細資訊,請參閱 SELECT - ORDER BY 子句

範例

本文中的 Transact-SQL 程式代碼範例會使用 AdventureWorks2022AdventureWorksDW2022 範例資料庫,您可以從 Microsoft SQL Server 範例和社群專案 首頁下載。

類別 代表性語法元素
基本語法 TOP * PERCENT
包括相同值 WITH TIES
限制受 DELETE、INSERT 或 UPDATE 影響的資料列 DELETEINSERTUPDATE

基本語法

本節中的範例示範 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 個數據列的三位員工系結。