Эквивалент LIMIT и OFFSET для SQL Server? - PullRequest
154 голосов
/ 25 января 2010

В PostgreSQL есть ключевые слова Limit и Offset, которые позволяют очень легко разбивать наборы результатов на страницы.

Каков эквивалентный синтаксис для Sql Server?

Ответы [ 14 ]

204 голосов
/ 13 февраля 2012

Эта функция теперь упрощена в SQL Server 2012. Это работает с SQL Server 2012 и далее.

Предел со смещением для выбора от 11 до 20 строк в SQL Server:

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • OFFSET: количество пропущенных строк
  • NEXT: необходимое количество следующих строк

Ссылка: https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

132 голосов
/ 25 января 2010

Эквивалент 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 должен использовать для этого индексацию по одному, а не обычную индексацию по нулю.

23 голосов
/ 27 марта 2013
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().

11 голосов
/ 25 января 2010

Вы можете использовать ROW_NUMBER в выражении Common Table для достижения этого.

;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
3 голосов
/ 22 февраля 2017

Для меня использование 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 у меня не сработало.

2 голосов
/ 27 июля 2017
-- @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
2 голосов
/ 14 ноября 2013

Самое близкое, что я мог сделать, это

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

2 голосов
/ 27 февраля 2013

Добавляя небольшую вариацию решения Аарона, я обычно параметризую номер страницы (@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
2 голосов
/ 17 августа 2011

Здесь здесь кто-то рассказывает об этой функции в sql 2011, печально, что они выбирают немного другое ключевое слово "OFFSET / FETCH", но это не стандартно, тогда хорошо.

2 голосов
/ 06 июля 2011

Другой образец:

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;
...