SQL Server 的 LIMIT 和 OFFSET 等效吗?

发布于 2024-08-18 17:57:03 字数 115 浏览 7 评论 0原文

在 PostgreSQL 中,有 LimitOffset 关键字,可以非常轻松地对结果集进行分页。

SQL Server 的等效语法是什么?

In PostgreSQL there is the Limit and Offset keywords which will allow very easy pagination of result sets.

What is the equivalent syntax for SQL Server?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

秋日私语 2024-08-25 17:57:03

SQL Server 2012 中现在可以轻松实现此功能。
从 SQL Server 2012 开始,此功能有效。

在 SQL Server 中限制选择 11 到 20 行的偏移量:

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • ORDER BY:必需
  • OFFSET:可选的跳过行数
  • NEXT:必需的跳过行数下一行

参考: https ://learn.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql

This feature is now made easy in SQL Server 2012.
This is working from SQL Server 2012 onwards.

Limit with offset to select 11 to 20 rows in SQL Server:

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • ORDER BY: required
  • OFFSET: optional number of skipped rows
  • NEXT: required number of next rows

Reference: https://learn.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql

九厘米的零° 2024-08-25 17:57:03

LIMIT 等效的是 SET ROWCOUNT,但如果您想要通用分页,最好编写如下查询:

;WITH Results_CTE AS
(
    SELECT
        Col1, Col2, ...,
        ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
    FROM Table
    WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= @Offset
AND RowNum < @Offset + @Limit

这里的优点是偏移量和限制的参数化,以防万一您决定更改分页选项(或允许用户这样做)。

注意@Offset 参数应使用从一开始的索引,而不是正常的从零开始的索引。

The equivalent of LIMIT is SET ROWCOUNT, but if you want generic pagination it's better to write a query like this:

;WITH Results_CTE AS
(
    SELECT
        Col1, Col2, ...,
        ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
    FROM Table
    WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= @Offset
AND RowNum < @Offset + @Limit

The advantage here is the parameterization of the offset and limit in case you decide to change your paging options (or allow the user to do so).

Note: the @Offset parameter should use one-based indexing for this rather than the normal zero-based indexing.

看春风乍起 2024-08-25 17:57:03
select top {LIMIT HERE} * from (
      select *, ROW_NUMBER() over (order by {ORDER FIELD}) as r_n_n 
      from {YOUR TABLES} where {OTHER OPTIONAL FILTERS}
) xx where r_n_n >={OFFSET HERE}

注意事项:
此解决方案仅适用于 SQL Server 2005 或更高版本,因为这是在实施 ROW_NUMBER() 时实现的。

select top {LIMIT HERE} * from (
      select *, ROW_NUMBER() over (order by {ORDER FIELD}) as r_n_n 
      from {YOUR TABLES} where {OTHER OPTIONAL FILTERS}
) xx where r_n_n >={OFFSET HERE}

A note:
This solution will only work in SQL Server 2005 or above, since this was when ROW_NUMBER() was implemented.

沙沙粒小 2024-08-25 17:57:03

您可以在公共表表达式中使用 ROW_NUMBER 来实现此目的。

;WITH My_CTE AS
(
     SELECT
          col1,
          col2,
          ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
)
SELECT
     col1,
     col2
FROM
     My_CTE
WHERE
     row_number BETWEEN @start_row AND @end_row

You can use ROW_NUMBER in a Common Table Expression to achieve this.

;WITH My_CTE AS
(
     SELECT
          col1,
          col2,
          ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
)
SELECT
     col1,
     col2
FROM
     My_CTE
WHERE
     row_number BETWEEN @start_row AND @end_row
森罗 2024-08-25 17:57:03

特别是对于 SQL-SERVER,您可以通过许多不同的方式来实现这一点。对于给定的实际示例,我们在此处采用了 Customer 表。

示例 1:使用“SET ROWCOUNT”

SET ROWCOUNT 10
SELECT CustomerID, CompanyName from Customers
ORDER BY CompanyName

要返回所有行,请将 ROWCOUNT 设置为 0

SET ROWCOUNT 0  
SELECT CustomerID, CompanyName from Customers
    ORDER BY CompanyName

>示例 2:使用“ROW_NUMBER 和 OVER”

With Cust AS
( SELECT CustomerID, CompanyName,
ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
FROM Customers )
select *
from Cust
Where RowNumber Between 0 and 10

示例 3:使用“OFFSET 和 FETCH”,但使用此“ORDER BY”是强制性的

SELECT CustomerID, CompanyName FROM Customers
ORDER BY CompanyName
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY

希望这对您有帮助。

Specifically for SQL-SERVER you can achieve that in many different ways.For given real example we took Customer table here.

Example 1: With "SET ROWCOUNT"

SET ROWCOUNT 10
SELECT CustomerID, CompanyName from Customers
ORDER BY CompanyName

To return all rows, set ROWCOUNT to 0

SET ROWCOUNT 0  
SELECT CustomerID, CompanyName from Customers
    ORDER BY CompanyName

Example 2: With "ROW_NUMBER and OVER"

With Cust AS
( SELECT CustomerID, CompanyName,
ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
FROM Customers )
select *
from Cust
Where RowNumber Between 0 and 10

Example 3 : With "OFFSET and FETCH", But with this "ORDER BY" is mandatory

SELECT CustomerID, CompanyName FROM Customers
ORDER BY CompanyName
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY

Hope this helps you.

儭儭莪哋寶赑 2024-08-25 17:57:03
-- @RowsPerPage  can be a fixed number and @PageNumber number can be passed 
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 2

SELECT *

FROM MemberEmployeeData

ORDER BY EmployeeNumber

OFFSET @PageNumber*@RowsPerPage ROWS

FETCH NEXT 10 ROWS ONLY
-- @RowsPerPage  can be a fixed number and @PageNumber number can be passed 
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 2

SELECT *

FROM MemberEmployeeData

ORDER BY EmployeeNumber

OFFSET @PageNumber*@RowsPerPage ROWS

FETCH NEXT 10 ROWS ONLY
瞎闹 2024-08-25 17:57:03

对我来说,一起使用 OFFSET 和 FETCH 很慢,所以我使用了 TOP 和 OFFSET 的组合,如下所示(速度更快):

SELECT TOP 20 * FROM (SELECT columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

注意: 如果您在同一个查询中同时使用 TOP 和 OFFSET,例如:

SELECT TOP 20 columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS

然后你会得到一个错误,因此如果要一起使用 TOP 和 OFFSET,你需要用子查询将其分开。

如果您需要使用 SELECT DISTINCT,则查询如下:

SELECT TOP 20 FROM (SELECT DISTINCT columname1, columname2
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

注意: 将 SELECT ROW_NUMBER 与 DISTINCT 一起使用对我来说不起作用。

For me the use of OFFSET and FETCH together was slow, so I used a combination of TOP and OFFSET like this (which was faster):

SELECT TOP 20 * FROM (SELECT columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Note: If you use TOP and OFFSET together in the same query like:

SELECT TOP 20 columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS

Then you get an error, so for use TOP and OFFSET together you need to separate it with a sub-query.

And if you need to use SELECT DISTINCT then the query is like:

SELECT TOP 20 FROM (SELECT DISTINCT columname1, columname2
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Note: The use of SELECT ROW_NUMBER with DISTINCT did not work for me.

雨落□心尘 2024-08-25 17:57:03

在 Aaronaught 的解决方案上添加轻微的变化,我通常参数化页码 (@PageNum) 和页面大小 (@PageSize)。这样,每个页面单击事件仅发送请求的页码以及可配置的页面大小:

begin
    with My_CTE  as
    (
         SELECT col1,
              ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
    )
    select * from My_CTE
            WHERE RowNum BETWEEN (@PageNum - 1) * (@PageSize + 1) 
                              AND @PageNum * @PageSize

end

Adding a slight variation on Aaronaught's solution, I typically parametrize page number (@PageNum) and page size (@PageSize). This way each page click event just sends in the requested page number along with a configurable page size:

begin
    with My_CTE  as
    (
         SELECT col1,
              ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
    )
    select * from My_CTE
            WHERE RowNum BETWEEN (@PageNum - 1) * (@PageSize + 1) 
                              AND @PageNum * @PageSize

end
野味少女 2024-08-25 17:57:03

另一个样本:

declare @limit int 
declare @offset int 
set @offset = 2;
set @limit = 20;
declare @count int
declare @idxini int 
declare @idxfim int 
select @idxfim = @offset * @limit
select @idxini = @idxfim - (@limit-1);
WITH paging AS
    (
        SELECT 
             ROW_NUMBER() OVER (order by object_id) AS rowid, *
        FROM 
            sys.objects 
    )
select *
    from 
        (select COUNT(1) as rowqtd from paging) qtd, 
            paging 
    where 
        rowid between @idxini and @idxfim
    order by 
        rowid;

Another sample :

declare @limit int 
declare @offset int 
set @offset = 2;
set @limit = 20;
declare @count int
declare @idxini int 
declare @idxfim int 
select @idxfim = @offset * @limit
select @idxini = @idxfim - (@limit-1);
WITH paging AS
    (
        SELECT 
             ROW_NUMBER() OVER (order by object_id) AS rowid, *
        FROM 
            sys.objects 
    )
select *
    from 
        (select COUNT(1) as rowqtd from paging) qtd, 
            paging 
    where 
        rowid between @idxini and @idxfim
    order by 
        rowid;
陌路黄昏 2024-08-25 17:57:03

这里有人讲述sql 2011 中的此功能,遗憾的是他们选择了一点不同的关键字“OFFSET / FETCH”,但它不是标准的,那么好吧。

There is here someone telling about this feature in sql 2011, its sad they choose a little different keyword "OFFSET / FETCH" but its not standart then ok.

单身狗的梦 2024-08-25 17:57:03

我能做的最接近的是

select * FROM( SELECT *, ROW_NUMBER() over (ORDER BY ID ) as ct from [db].[dbo].[table] ) sub where ct > fromNumber  and ct <= toNumber

我猜类似于 select * from [db].[dbo].[table] LIMIT 0, 10

The closest I could make is

select * FROM( SELECT *, ROW_NUMBER() over (ORDER BY ID ) as ct from [db].[dbo].[table] ) sub where ct > fromNumber  and ct <= toNumber

Which I guess similar to select * from [db].[dbo].[table] LIMIT 0, 10

说不完的你爱 2024-08-25 17:57:03

详细阐述 Somnath-Muluk 的答案只需使用:

SELECT *
FROM table_name_here
ORDER BY (SELECT NULL AS NOORDER)
OFFSET 9 ROWS 
FETCH NEXT 25 ROWS ONLY 

不添加任何额外的列。
在 SQL Server 2019 中进行了测试,但我想也可以在旧版本中使用。

Elaborating the Somnath-Muluk's answer just use:

SELECT *
FROM table_name_here
ORDER BY (SELECT NULL AS NOORDER)
OFFSET 9 ROWS 
FETCH NEXT 25 ROWS ONLY 

w/o adding any extra column.
Tested in SQL Server 2019, but I guess could work in older ones as well.

月依秋水 2024-08-25 17:57:03
select top (@TakeCount) * --FETCH NEXT
from(
    Select  ROW_NUMBER() OVER (order by StartDate) AS rowid,*
    From YourTable
)A
where Rowid>@SkipCount --OFFSET
select top (@TakeCount) * --FETCH NEXT
from(
    Select  ROW_NUMBER() OVER (order by StartDate) AS rowid,*
    From YourTable
)A
where Rowid>@SkipCount --OFFSET
伊面 2024-08-25 17:57:03
@nombre_row :nombre ligne par page  
@page:numero de la page

//--------------code sql---------------

declare  @page int,@nombre_row int;
    set @page='2';
    set @nombre_row=5;
    SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY etudiant_ID ) AS RowNum, *
      FROM      etudiant

    ) AS RowConstrainedResult
WHERE   RowNum >= ((@page-1)*@nombre_row)+1
    AND RowNum < ((@page)*@nombre_row)+1
ORDER BY RowNum
@nombre_row :nombre ligne par page  
@page:numero de la page

//--------------code sql---------------

declare  @page int,@nombre_row int;
    set @page='2';
    set @nombre_row=5;
    SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY etudiant_ID ) AS RowNum, *
      FROM      etudiant

    ) AS RowConstrainedResult
WHERE   RowNum >= ((@page-1)*@nombre_row)+1
    AND RowNum < ((@page)*@nombre_row)+1
ORDER BY RowNum
匿名。 2024-08-25 17:57:03

由于尚未提供此代码:

SELECT TOP @limit f1, f2, f3...
FROM t1
WHERE c1 = v1, c2 > v2...
AND
    t1.id NOT IN
        (SELECT TOP @offset id
         FROM t1
         WHERE c1 = v1, c2 > v2...
         ORDER BY o1, o2...)
ORDER BY o1, o2...

重要提示:

  • ORDER BY 必须相同
  • @limit 可以替换为要检索的结果数,
  • @offset是要跳过的结果数
  • 请与以前的解决方案比较性能,因为它们可能更高效。
  • 此解决方案重复 whereorder by 子句,如果它们超出,将提供不正确的结果 同步order by 是明确存在的
  • 另一方面,如果需要的话,

Since nobody provided this code yet:

SELECT TOP @limit f1, f2, f3...
FROM t1
WHERE c1 = v1, c2 > v2...
AND
    t1.id NOT IN
        (SELECT TOP @offset id
         FROM t1
         WHERE c1 = v1, c2 > v2...
         ORDER BY o1, o2...)
ORDER BY o1, o2...

Important points:

  • ORDER BY must be identical
  • @limit can be replaced with number of results to retrieve,
  • @offset is number of results to skip
  • Please compare performance with previous solutions as they may be more efficient
  • this solution duplicates where and order by clauses, and will provide incorrect results if they are out of sync
  • on the other hand order by is there explicitly if that's what's needed
烏雲後面有陽光 2024-08-25 17:57:03

在 SQL Server 中,您可以将 TOP 与 ROW_NUMBER() 一起使用

In SQL server you would use TOP together with ROW_NUMBER()

旧城空念 2024-08-25 17:57:03

我假设,在 C# 表达式/LINQ 语句中,skip 和 take 生成以下 SQL 命令

DECLARE @p0 Int = 1
DECLARE @p1 Int = 3
SELECT [t1].[Id]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Id]
    FROM [ShoppingCart] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]

I assume that, In C# Expression/LINQ statement of skip and take generating below SQL Command

DECLARE @p0 Int = 1
DECLARE @p1 Int = 3
SELECT [t1].[Id]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Id]
    FROM [ShoppingCart] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]
荭秂 2024-08-25 17:57:03

因为,我测试了更多次,这个脚本更有用,每页100万条记录,100条记录,分页工作速度更快,我的电脑执行这个脚本0秒,而与mysql相比,有自己的限制和偏移量,大约4.5秒才能得到结果。

有人可能错过了 Row_Number() 总是按特定字段排序的理解。如果我们需要按顺序只定义行,则应使用:

ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

SELECT TOP {LIMIT} * FROM (
      SELECT TOP {LIMIT} + {OFFSET} ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ROW_NO,*
      FROM  {TABLE_NAME}
) XX WHERE ROW_NO > {OFFSET}

说明:

  • {LIMIT}:每页的记录数
  • {OFFSET}:跳过记录数

Since, I test more times this script more useful by 1 million records each page 100 records with pagination work faster my PC execute this script 0 sec while compare with mysql have own limit and offset about 4.5 sec to get the result.

Someone may miss understanding Row_Number() always sort by specific field. In case we need to define only row in sequence should use:

ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

SELECT TOP {LIMIT} * FROM (
      SELECT TOP {LIMIT} + {OFFSET} ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ROW_NO,*
      FROM  {TABLE_NAME}
) XX WHERE ROW_NO > {OFFSET}

Explain:

  • {LIMIT}: Number of records for each page
  • {OFFSET}: Number of skip records
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文