SELECT - ORDER BY 子句 (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsMicrosoft Fabric中的SQL分析端点Microsoft Fabric中的仓库Microsoft Fabric中的SQL数据库

对 SQL Server 中的查询返回的数据进行排序。 可以使用此子句执行以下操作:

  • 按指定的列列表对查询的结果集进行排序,并有选择地将返回的行限制为指定范围。 除非 ORDER BY 指定了子句,否则无法保证在结果集中返回行的顺序。

  • 确定将排名函数值应用于结果集的顺序。

Transact-SQL 语法约定

Note

ORDER BY在 Azure Synapse Analytics 中不支持 SELECT/INTO 或 CREATE TABLE AS SELECT (CTAS) 语句。

Syntax

SQL Server、Azure SQL 数据库、Azure SQL 托管实例 和 SQL database in Fabric 的语法

ORDER BY order_by_expression
    [ COLLATE collation_name ]
    [ ASC | DESC ]
    [ , ...n ]
[ <offset_fetch> ]

<offset_fetch> ::=
{
    OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }
    [
      FETCH { FIRST | NEXT } { integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY
    ]
}

Fabric Data Warehouse和SQL分析端点的语法。

ORDER BY
{
    order_by_expression
    [ COLLATE collation_name ]
    [ ASC | DESC ]
    [ , ...n ]
  | ALL [ ASC | DESC ]
}
[ <offset_fetch> ]

<offset_fetch> ::=
{
    OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }
    [
      FETCH { FIRST | NEXT } { integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY
    ]
}

Azure Synapse Analytics 的语法:

[ ORDER BY
    {
    order_by_expression
    [ ASC | DESC ]
    } [ , ...n ]
]

Arguments

order_by_expression

指定用于对查询结果集进行排序的列或表达式。 可以将排序列指定为名称或列别名,也可以指定为表示列在选择列表中位置的非负整数。

可以指定多个排序列。 别名必须是唯一的。 子句中 ORDER BY 排序列的顺序定义排序结果集的组织。 结果集按第一列排序,然后排序列表按第二列排序,依此类而行。

在子句中引用的 ORDER BY 列名必须与选择列表中的列或列别名相对应,或者对应于在子句中指定的 FROM 表中定义的列,且没有任何歧义。 ORDER BY如果子句从选择列表中引用列别名,请自行使用列别名。 请勿将列别名用作子句中 ORDER BY 表达式的一部分。

例如:

  • 正确的用法:

    SELECT SCHEMA_NAME(schema_id) AS SchemaName
    FROM sys.objects
    ORDER BY SchemaName; -- correct
    
  • 用法不正确:

    SELECT SCHEMA_NAME(schema_id) AS SchemaName
    FROM sys.objects
    ORDER BY SchemaName + ''; -- wrong
    

COLLATE collation_name

指定 ORDER BY 应根据 collation_name中指定的排序规则执行该作,而不是根据表或视图中定义的列的排序规则执行。 collation_name可以是 Windows 排序规则名称或 SQL 排序规则名称。 有关详细信息,请参阅 排序规则和 Unicode 支持。 COLLATE仅适用于 char、varchar、nchar 和 nvarchar 类型的列。

ASC |描述

指定应当按升序或降序对指定列中的值进行排序。 ASC 将按照从最低值到最高值的顺序排序。 DESC 将按照从最高值到最低值的顺序排序。 ASC 是默认排序顺序。 NULL 值被视为最低的可能值。

ALL

适用于:仅限Fabric Data Warehouse和SQL分析端点。

该 ORDER BY ALL 子句指定结果集按投影列表中的所有列排序。

SELECT name, object_id, SCHEMA_NAME(schema_id) AS schema_name
, CONCAT_WS('.',  SCHEMA_NAME(schema_id), name) AS full_name
FROM sys.objects
ORDER BY ALL;

可选 ASC 和 DESC 关键词决定所有投影列的排序顺序。 ASC 将所有值从最低到最高排序,同时 DESC 将所有值从高到低排序。 如果这两个选项都未指定,则 ASC 默认使用 。 NULL 排序时,值被视为最低值。

OFFSET { integer_constantoffset_row_count_expression } { ROW | ROWS } |

适用于:SQL Server 2012(11.x)及以后版本,Azure SQL 数据库 和 Azure SQL 托管实例,Microsoft Fabric 中的仓库,Microsoft Fabric 中的 SQL 分析端点。

指定要在查询开始返回查询表达式中的行之前要跳过的行数。 该值可以是大于或等于零的整数常量或表达式。

offset_row_count_expression 可以是变量、参数或常量标量子查询 。 使用子查询时,它不能引用在外部查询范围中定义的任何列。 也就是说,它不能与外部查询相关联。

ROW 并且 ROWS 是同义词,用于 ANSI 兼容性。

在查询执行计划中,偏移行计数值显示在查询运算符的 Offset 属性中 TOP 。

FETCH { FIRST | NEXT } { integer_constantfetch_row_count_expression } { ROW | ROWS } ONLY

适用于:SQL Server 2012(11.x)及以后版本,Azure SQL 数据库 和 Azure SQL 托管实例,Microsoft Fabric 中的仓库,Microsoft Fabric 中的 SQL 分析端点。

指定要在处理子句后返回的 OFFSET 行数。 该值可以是大于或等于 1 的整数常量或表达式。

fetch_row_count_expression 可以是变量、参数或常量标量子查询 。 使用子查询时,它不能引用在外部查询范围中定义的任何列。 也就是说,它不能与外部查询相关联。

FIRST 并且 NEXT 是同义词,用于 ANSI 兼容性。

ROW 并且 ROWS 是同义词,用于 ANSI 兼容性。

在查询执行计划中,偏移行计数值显示在查询运算符的 Rows 或 Top 属性中 TOP 。

最佳做法

避免在 ORDER BY 子句中将整数指定为选择列表中的列的位置表示形式。 例如,尽管语句(如 SELECT ProductID, Name FROM Production.Production ORDER BY 2 有效),但与指定实际列名相比,用户可能会发现很难理解。 此外,对选择列表的更改(例如更改列顺序或添加新列)需要修改 ORDER BY 子句以避免意外的结果。

SELECT TOP (<n>)在语句中,始终使用子ORDER BY句。 这是可预测地指示哪些行 TOP 影响的唯一方法。 有关更多信息,请参见 TOP。

Interoperability

使用ORDER BY或SELECT...INTOINSERT...SELECT语句从另一个源插入行时,子ORDER BY句不保证以指定顺序插入行。

使用 OFFSET 和 FETCH 在视图中不会更改视图的可更新性属性。

Limitations

子句中的 ORDER BY 列数没有限制。 但是,子 ORDER BY 句中指定的列的总大小不能超过 8,060 字节。

不能在子句中使用类型为 ntext、text、image、geography、geometry 或 ORDER BY 的列。

当order_by_expression出现在排名函数中时,不能指定整数或常量。 有关详细信息,请参阅 SELECT - OVER 子句。

如果为子句中的 FROM 表名添加别名,则必须使用别名来限定子句中的 ORDER BY 列。

SELECT如果语句包含以下子句或运算符之一,则必须在 select 列表中定义子句中指定的ORDER BY列名和别名:

  • UNION 运算符
  • EXCEPT 运算符
  • INTERSECT 运算符
  • SELECT DISTINCT

此外,当语句包含一个或UNIONEXCEPT运算符时,第一个INTERSECT(左侧)查询的选择列表必须指定列名或列别名。

在使用 UNION、 EXCEPT或 INTERSECT 运算符的查询中,只能在语句末尾使用 ORDER BY 。 此限制仅适用于指定 UNION、 EXCEPT在顶级查询中, INTERSECT 而不是子查询时。 请参阅示例部分。

子 ORDER BY 句在视图、内联函数、派生表和子查询中无效,除非还指定 TOP 或 OFFSET 子 FETCH 句。 在这些ORDER BY对象中使用时,子句仅用于确定子句或TOP子OFFSET句返回FETCH的行。 ORDER BY除非查询本身中也指定了子句,否则ORDER BY子句不能保证查询这些构造时的有序结果。

OFFSET在索引视图或通过使用FETCH子句定义的视图中不支持和CHECK OPTION。

OFFSET 并 FETCH 可用于允许 TOP 且 ORDER BY 具有以下限制的任何查询:

  • 子 OVER 句不支持 OFFSET 和 FETCH.

  • 不能直接在 、、和语句中OFFSET指定FETCHINSERT,但可以在这些语句中定义的子查询中指定它们。UPDATEMERGEDELETE 例如,在语句中 INSERT INTO SELECT ,可以指定 OFFSET 和 FETCH 在语句中 SELECT 。

  • 在使用UNIONEXCEPT或INTERSECT运算符的查询中,只有指定查询结果顺序的最终查询可以指定OFFSET和FETCH。

  • 不能将 TOP 与同一查询表达式(在同一查询范围内)中的 OFFSET 和 FETCH 组合在一起。

使用 OFFSET 和 FETCH 限制返回的行

OFFSET使用 and FETCH 子句而不是TOP子句来实现查询分页解决方案,并限制发送到客户端应用程序的行数。

使用 OFFSET 和 FETCH 作为分页解决方案需要对返回到客户端应用程序的每个 数据页 运行一次查询。 例如,若要以 10 行增量返回查询的结果,必须执行查询一次以返回行 1 到 10 行,然后再次运行查询以返回行 11 到 20,依此等。 每个查询都是独立的,不会以任何方式与其他查询相关联。 此条件意味着,与使用游标(其中执行查询一次并在服务器上维护状态)不同,客户端应用程序负责跟踪状态。 若要在查询请求之间使用 OFFSET 和 FETCH实现稳定结果,必须满足以下条件:

  1. 查询使用的基础数据不会更改。 也就是说,查询不会更新行,也不会使用快照或可序列化事务隔离在单个事务中执行查询中对页面的所有请求。 有关这些交易隔离级别的更多信息,请参见 SET TRANSACTION ISOLATION LEVEL。

  2. 子 ORDER BY 句包含保证唯一的列或列的组合。

请参阅“示例”部分中的单个事务中的“运行多个查询”示例。

如果分页解决方案中的一致执行计划很重要,请考虑对参数OPTIMIZE FOR使用OFFSET查询提示FETCH。 请参阅“示例”部分中的 OFFSET 和 FETCH 值的指定表达式。 有关详细信息 OPTIMIZE FOR,请参阅 查询提示。

Examples

本文中的代码示例使用AdventureWorks2025了 、 AdventureWorksDW2025或AdventureWorksLT2025示例数据库,您可以从 Azure Data SQL Samples Repository 的 GitHub 仓库下载。

Category 作为特征的语法元素
基本语法 ORDER BY
指定升序和降序 DESC 或 ASC
指定排序规则 COLLATE
指定条件顺序 CASE 表达式
在排名函数中使用 ORDER BY 排名函数
限制返回的行数 OFFSET 和 FETCH
将 ORDER BY 与 UNION、EXCEPT 和 INTERSECT 配合使用 UNION

基本语法

本节中的示例演示了使用最低所需语法的 ORDER BY 子句的基本功能。

A. 指定在选择列表中定义的单个列

以下示例按数值 ProductID 列对结果集进行顺序。 由于未指定排序顺序,因此查询使用默认升序。

USE AdventureWorks2025;
GO

SELECT ProductID,
       Name
FROM Production.Product
WHERE Name LIKE 'Lock Washer%'
ORDER BY ProductID;

B. 指定在选择列表中未定义的列

下面的示例按选择列表不包含的列对结果集进行排序,但该 FROM 子句指定包含该列的表。

USE AdventureWorks2025;
GO

SELECT ProductID,
       Name,
       Color
FROM Production.Product
ORDER BY ListPrice;

C. 将别名指定为排序列

以下示例将列别名 SchemaName 指定为排序顺序列。

USE AdventureWorks2025;
GO

SELECT name,
       SCHEMA_NAME(schema_id) AS SchemaName
FROM sys.objects
WHERE type = 'U'
ORDER BY SchemaName;

D. 将表达式指定为排序列

以下示例将表达式作为排序列。 该表达式是使用 DATEPART 函数根据员工雇用年份对结果集进行排序来定义的。

USE AdventureWorks2025;
GO

SELECT BusinessEntityID,
       JobTitle,
       HireDate
FROM HumanResources.Employee
ORDER BY DATEPART(year, HireDate);

指定升序和降序排序顺序

A. 指定降序

以下示例按 ProductID 数值列降序对结果集进行排序。

USE AdventureWorks2025;
GO

SELECT ProductID,
       Name
FROM Production.Product
WHERE Name LIKE 'Lock Washer%'
ORDER BY ProductID DESC;

B. 指定升序

以下示例按 Name 列升序对结果集进行排序。 字符按字母顺序排序,而不是数值顺序。 也就是说,10 排在 2 之前。

USE AdventureWorks2025;
GO

SELECT ProductID,
       Name
FROM Production.Product
WHERE Name LIKE 'Lock Washer%'
ORDER BY Name ASC;

C. 同时指定升序和降序

以下示例按两个列对结果集进行排序。 先按 FirstName 列升序对查询结果集进行排序,然后按 LastName 列降序进行排序。

USE AdventureWorks2025;
GO

SELECT LastName,
       FirstName
FROM Person.Person
WHERE LastName LIKE 'R%'
ORDER BY FirstName ASC, LastName DESC;

指定排序规则

以下示例演示如何在子句中 ORDER BY 指定排序规则可以更改查询结果的返回顺序。 将创建一个表,其中包含一个使用不区分大小写和重音的排序规则定义的列。 使用各种大小写和重音差异插入值。 由于子句中 ORDER BY 未指定排序规则,因此第一个查询在对值进行排序时使用列的排序规则。 在第二个查询中,子句中 ORDER BY 指定区分大小写、区分重音的排序规则,这会更改返回行的顺序。

USE tempdb;
GO

CREATE TABLE #t1
(
    name NVARCHAR (15) COLLATE Latin1_General_CI_AI
);

INSERT INTO #t1
VALUES (N'Sánchez'),
       (N'Sanchez'),
       (N'sánchez'),
       (N'sanchez');

-- This query uses the collation specified for the column 'name' for sorting.
SELECT name
FROM #t1
ORDER BY name;

-- This query uses the collation specified in the ORDER BY clause for sorting.
SELECT name
FROM #t1
ORDER BY name COLLATE Latin1_General_CS_AS;

指定条件顺序

以下示例使用 CASE 子句中的 ORDER BY 表达式根据给定的列值有条件地确定行的排序顺序。 在第一个示例中,会计算 SalariedFlag 表中 HumanResources.Employee 列的值。 SalariedFlag 设置为 1 的员工将按 BusinessEntityID 以降序顺序返回。 SalariedFlag 设置为 0 的员工将按 BusinessEntityID 以升序顺序返回。 在第二个示例中,当 TerritoryName 列等于“美国”时,结果集会按 CountryRegionName 列排序,对于所有其他行则按 CountryRegionName 排序。

SELECT BusinessEntityID,
       SalariedFlag
FROM HumanResources.Employee
ORDER BY
    CASE SalariedFlag
        WHEN 1 THEN BusinessEntityID
    END DESC,
    CASE
        WHEN SalariedFlag = 0 THEN BusinessEntityID
    END;
SELECT BusinessEntityID,
       LastName,
       TerritoryName,
       CountryRegionName
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL
ORDER BY
    CASE CountryRegionName
        WHEN 'United States' THEN TerritoryName ELSE CountryRegionName
    END;

在排名函数中使用 ORDER BY

以下示例使用ORDER BY排名函数ROW_NUMBER、RANK和 DENSE_RANKNTILE.

USE AdventureWorks2025;
GO

SELECT p.FirstName,
       p.LastName,
       ROW_NUMBER() OVER (ORDER BY a.PostalCode) AS "Row Number",
       RANK() OVER (ORDER BY a.PostalCode) AS "Rank",
       DENSE_RANK() OVER (ORDER BY a.PostalCode) AS "Dense Rank",
       NTILE(4) OVER (ORDER BY a.PostalCode) AS "Quartile",
       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;

限制返回的行数

适用于:SQL Server 2012(11.x)及更高版本、Azure SQL 数据库和Azure SQL 托管实例。

以下示例使用 OFFSET 和 FETCH 限制查询返回的行数。

A. 指定 OFFSET 和 FETCH 值的整数常量

以下示例将整数常量指定为 and OFFSET 子句的值FETCH。 第一个查询返回所有按 DepartmentID 列排序的行。 将此查询返回的结果与后面的两个查询的结果进行比较。 下一个查询使用子句 OFFSET 5 ROWS 跳过前五行并返回所有剩余行。 最终查询使用 OFFSET 0 ROWS 子句从第一行开始,然后使用 FETCH NEXT 10 ROWS ONLY 将返回的行限制为排序的结果集中的 10 行。

USE AdventureWorks2025;
GO

-- Return all rows sorted by the column DepartmentID.
SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID;

-- Skip the first 5 rows from the sorted result set and return all remaining rows.
SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID OFFSET 5 ROWS;

-- Skip 0 rows and return only the first 10 rows from the sorted result set.
SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY;

B. 指定 OFFSET 和 FETCH 值的变量

以下示例声明变量@RowsToSkip并在@FetchRows和OFFSET子句中FETCH指定这些变量。

USE AdventureWorks2025;
GO

-- Specifying variables for OFFSET and FETCH values
DECLARE @RowsToSkip AS TINYINT = 2,
        @FetchRows AS TINYINT = 8;

SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC OFFSET @RowsToSkip ROWS
FETCH NEXT @FetchRows ROWS ONLY;

C. 指定 OFFSET 和 FETCH 值的表达式

下面的示例使用表达式 @StartingRowNumber - 1 来指定 OFFSET 值和表达式 @EndingRowNumber - @StartingRowNumber + 1 来指定 FETCH 值。 此外,还指定了查询提示 OPTIMIZE FOR。 使用此提示在编译和优化查询时为局部变量提供特定值。 仅在查询优化期间使用该值,在查询执行期间不使用该值。 有关详细信息,请参阅 查询提示。

USE AdventureWorks2025;
GO

-- Specifying expressions for OFFSET and FETCH values
DECLARE @StartingRowNumber AS TINYINT = 1,
        @EndingRowNumber AS TINYINT = 8;

SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC OFFSET @StartingRowNumber - 1 ROWS
FETCH NEXT @EndingRowNumber - @StartingRowNumber + 1 ROWS ONLY
OPTION (OPTIMIZE FOR (@StartingRowNumber = 1, @EndingRowNumber = 20));

D. 为 OFFSET 和 FETCH 值指定常量标量子查询

以下示例使用常量标量子查询来定义子句的值 FETCH 。 该子查询从 PageSize 表的 dbo.AppSettings 列中返回单个值。

-- Specifying a constant scalar subquery
USE AdventureWorks2025;
GO

CREATE TABLE dbo.AppSettings
(
    AppSettingID INT NOT NULL,
    PageSize INT NOT NULL
);

INSERT INTO dbo.AppSettings
VALUES (1, 10);

DECLARE @StartingRowNumber AS TINYINT = 1;

SELECT DepartmentID,
       Name,
       GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC
OFFSET @StartingRowNumber ROWS
FETCH NEXT (SELECT PageSize
            FROM dbo.AppSettings
            WHERE AppSettingID = 1) ROWS ONLY;

E. 在单个事务中运行多个查询

以下示例说明一种实现分页解决方案的方法,以确保在查询的所有请求中返回稳定的结果。 查询使用快照隔离级别在单个事务中执行,子句中指定的 ORDER BY 列可确保列唯一性。

USE AdventureWorks2025;
GO

-- Ensure the database can support the snapshot isolation level set for the query.
IF (SELECT snapshot_isolation_state
    FROM sys.databases
    WHERE name = N'AdventureWorks2025') = 0
ALTER DATABASE AdventureWorks2025
SET ALLOW_SNAPSHOT_ISOLATION ON;

-- Set the transaction isolation level to SNAPSHOT for this query.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

-- Beginning the transaction.
BEGIN TRANSACTION;

-- Declare and set the variables for the OFFSET and FETCH values.
DECLARE @StartingRowNumber AS INT = 1,
        @RowCountPerPage AS INT = 3;

-- Create the condition to stop the transaction after all rows have been returned.
WHILE (SELECT COUNT(*)
       FROM HumanResources.Department) >= @StartingRowNumber
    BEGIN
         -- Run the query until the stop condition is met.
        SELECT DepartmentID,
               Name,
               GroupName
        FROM HumanResources.Department
        ORDER BY DepartmentID ASC OFFSET @StartingRowNumber - 1 ROWS
        FETCH NEXT @RowCountPerPage ROWS ONLY;

        -- Increment @StartingRowNumber value.
        SET @StartingRowNumber = @StartingRowNumber + @RowCountPerPage;
        CONTINUE;
    END
COMMIT TRANSACTION;

将 ORDER BY 与 UNION、EXCEPT 和 INTERSECT 配合使用

当查询使用语句末尾的 UNION子 EXCEPT句或 INTERSECT 运算符 ORDER BY 时。 查询对组合查询的结果进行排序。 以下示例返回所有红色或黄色的产品,并按 ListPrice 列对合并的列表进行排序。

USE AdventureWorks2025;
GO

SELECT Name,
       Color,
       ListPrice
FROM Production.Product
WHERE Color = 'Red' -- ORDER BY cannot be specified here.
UNION ALL
SELECT Name,
       Color,
       ListPrice
FROM Production.Product
WHERE Color = 'Yellow'
ORDER BY ListPrice ASC;

示例:Azure Synapse Analytics

以下示例演示按 EmployeeKey 数值列升序对结果集进行排序。

-- Uses AdventureWorks
SELECT EmployeeKey,
       FirstName,
       LastName
FROM DimEmployee
WHERE LastName LIKE 'A%'
ORDER BY EmployeeKey;

以下示例按 EmployeeKey 数值列降序对结果集进行排序。

-- Uses AdventureWorks
SELECT EmployeeKey,
       FirstName,
       LastName
FROM DimEmployee
WHERE LastName LIKE 'A%'
ORDER BY EmployeeKey DESC;

以下示例按 LastName 列对结果集进行排序。

-- Uses AdventureWorks
SELECT EmployeeKey,
       FirstName,
       LastName
FROM DimEmployee
WHERE LastName LIKE 'A%'
ORDER BY LastName;

以下示例按照两列进行排序。 此查询首先按 FirstName 列以升序排序,然后按 FirstName 列以降序对常见 LastName 值降序排序。

-- Uses AdventureWorks
SELECT EmployeeKey,
       FirstName,
       LastName
FROM DimEmployee
WHERE LastName LIKE 'A%'
ORDER BY LastName, FirstName;