TOP (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric 中的 SQL 终结点Microsoft Fabric 中的仓库Microsoft Fabric SQL 数据库

将在查询结果集中返回的行数限制到 SQL Server 中的指定行数或行的百分比。 将 TOPORDER BY 子句一起使用时,结果集限制为第一个 n 有序行数。 否则,TOP 按未定义的顺序返回第一个 n 行数。 使用此子句可以指定从 SELECT 语句返回的行数。 或者,使用 TOP 指定受 INSERTUPDATEMERGEDELETE 语句影响的行。

Transact-SQL 语法约定

语法

SQL Server 和 Azure SQL 数据库的语法:

[
    TOP (expression) [ PERCENT ]
    [ WITH TIES ]
]

Azure Synapse Analytics 和分析平台系统的语法(PDW):

[
    TOP ( expression )
    [ WITH TIES ]
]

参数

expression

指定要返回的行数的数值表达式。 如果指定 PERCENT,则 表达式 隐式转换为 浮点数 值。 否则,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 子句来实现查询分页解决方案。 分页解决方案(即向客户端发送区块或 )更易于使用 OFFSETFETCH 子句实现。 有关详细信息,请参阅 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

局限性

TOP 用于 INSERTUPDATEMERGEDELETE时,引用的行不会按任何顺序排列。 而且,不能在这些语句中直接指定 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 限制删除的行数

TOP (<n>) 子句与 DELETE一起使用时,删除操作是在未定义的 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 行,嵌套 Select 语句 (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 表中的前 5 名雇员的姓名和本年度到目前为止的销售数据。 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 子句更新表中的行。 将 TOP (<n>) 子句用于 UPDATE时,更新操作在未定义的行数上运行。 也就是说,UPDATE 语句选择满足 WHERE 子句中定义的条件的任何行数(n)。 下列示例将 10 个客户从一位销售人员分配给了另一位。

USE AdventureWorks2022;

UPDATE TOP (10)
Sales.Store
SET SalesPersonID = 276
WHERE SalesPersonID = 275;
GO

如果必须使用 TOP 在有意义的计时表中应用更新,则必须在子选择语句中使用 TOPORDER 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 行的平局。