Смещение строки в SQL Server

Есть ли способ в SQL Server получить результаты, начинающиеся с заданного смещения? Например, в другом типе базы данных SQL это можно сделать:

SELECT * FROM MyTable OFFSET 50 LIMIT 25

чтобы получить результаты 51-75. Эта конструкция, похоже, не существует в SQL Server.

Как я могу выполнить это, не загружая все строки, которые мне не нужны? Благодарю!

Ответ 1

Я бы не использовал SELECT *. Укажите нужные столбцы, даже если они могут быть все.

SQL Server 2005 +

SELECT col1, col2 
FROM (
    SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
    FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow

SQL Server 2000

Эффективное пейджинг с помощью больших наборов результатов в SQL Server 2000

Более эффективный метод пейджинга с помощью больших наборов результатов

Ответ 2

Если вы будете обрабатывать все страницы в порядке, то просто запоминание последнего значения ключа, которое видно на предыдущей странице, и использование TOP (25) ... WHERE Key > @last_key ORDER BY Key может быть наилучшим образом выполненным методом, если существуют подходящие индексы, чтобы это можно было искать эффективно - или курсор API, если они этого не делают.

Для выбора произвольной страницы лучшим решением для SQL Server 2005 - 2008 R2, вероятно, является ROW_NUMBER и BETWEEN

Для SQL Server 2012+ вы можете использовать расширенный ORDER BY для этой потребности.

SELECT  *
FROM     MyTable 
ORDER BY OrderingColumn ASC 
OFFSET  50 ROWS 
FETCH NEXT 25 ROWS ONLY 

Хотя еще не видно, насколько хорошо будет выполняться этот параметр.

Ответ 3

Это один из способов (SQL2000)

SELECT * FROM
(
    SELECT TOP (@pageSize) * FROM
    (
        SELECT TOP (@pageNumber * @pageSize) *
        FROM tableName 
        ORDER BY columnName ASC
    ) AS t1 
    ORDER BY columnName DESC
) AS t2 
ORDER BY columnName ASC

и это другой способ (SQL 2005)

;WITH results AS (
    SELECT 
        rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
        , *
    FROM tableName 
) 
SELECT * 
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize

Ответ 4

Вы можете использовать функцию ROW_NUMBER(), чтобы получить то, что вы хотите:

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20

Ответ 5

Для таблиц с большим количеством столбцов данных я предпочитаю:

SELECT 
  tablename.col1,
  tablename.col2,
  tablename.col3,
  ...
FROM
(
  (
    SELECT
      col1
    FROM 
    (
      SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
      FROM tablename
      WHERE ([CONDITION])
    )
    AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
  )
  AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);

-

[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.

Он имеет намного лучшую производительность в таблицах с большими данными, такими как BLOB, потому что функция ROW_NUMBER должна просматривать только один столбец, и только соответствующие строки возвращаются со всеми столбцами.

Ответ 6

В SQL Server 2012 есть OFFSET.. FETCH, но вам нужно будет указать столбец ORDER BY.

Если у вас действительно нет явного столбца, который вы могли бы передать как столбец ORDER BY (как предлагали другие), то вы можете использовать этот трюк:

SELECT * FROM MyTable 
ORDER BY @@VERSION 
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

... или же

SELECT * FROM MyTable 
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

Мы используем его в jOOQ, когда пользователи не указывают явно порядок. Это тогда произведет довольно случайный заказ без каких-либо дополнительных затрат.

Ответ 7

Смотрите мой выбор для paginator

SELECT TOP @limit * FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (

     -- YOU SELECT HERE
     SELECT * FROM mytable


   ) myquery
) paginator
WHERE offset > @offset

Это разрешает разбиение на страницы;)

Ответ 8

SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable

Ответ 9

В зависимости от вашей версии вы не можете сделать это напрямую, но вы можете сделать что-то взломанное как

select top 25 *
from ( 
  select top 75 *
  from   table 
  order by field asc
) a 
order by field desc 

где "поле" - это ключ.

Ответ 10

Вы должны быть осторожны при использовании ROW_NUMBER() OVER (ORDER BY) как производительность довольно низкая. То же самое касается использования общих табличных выражений с ROW_NUMBER() что еще хуже. Я использую следующий фрагмент, который оказался немного быстрее, чем использование табличной переменной с идентификатором для предоставления номера страницы.

DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10

DECLARE @ROWCOUNT INT = @[email protected]
SET ROWCOUNT @ROWCOUNT

SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1

SELECT * FROM
(
    SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
    (
        SELECT *, 1 As SortConst FROM #ResultSet
    ) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT

DROP TABLE #ResultSet

Ответ 11

В результате отобразится 25 записей, исключая первые 50 записей, работающих в SQL Server 2012.

SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;

вы можете заменить ID как свое требование

Ответ 12

В SqlServer2005 вы можете сделать следующее:

DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10

SELECT 
    * 
FROM
(
   SELECT 
       row_number() 
   OVER 
      (ORDER BY column) AS rownum, column2, column3, .... columnX
   FROM   
     table
) AS A
WHERE 
 A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1) 

Ответ 13

Я использую этот метод для разбивки на страницы. Я не получаю все строки. Например, если моя страница должна отображать 100 лучших строк, я извлекаю только предложение 100 с where. Вывод SQL должен иметь уникальный ключ.

В таблице указано следующее:

ID, KeyId, Rank

Тот же ранг будет назначен для нескольких ключевых слов.

SQL select top 2 * from Table1 where Rank >= @Rank and ID > @Id

В первый раз я передаю 0 для обоих. Второй раз проходят 1 и 14. 3-й раз проходят 2 и 6....

Значение 10-й записи Ранг и идентификатор передаются на следующий

11  21  1
14  22  1
7   11  1
6   19  2
12  31  2
13  18  2

Это будет иметь наименьшее напряжение в системе

Ответ 14

Лучший способ сделать это, не тратя время на заказы, выглядит следующим образом:

select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY

требуется менее одной секунды!
лучшее решение для больших таблиц.

Ответ 15

Я искал этот ответ некоторое время (для общих запросов) и выяснил другой способ сделать это на SQL Server 2000+ с помощью ROWCOUNT и курсоров и без TOP или любой временной таблицы.

Используя SET ROWCOUNT [OFFSET+LIMIT], вы можете ограничить результаты и курсорами, перейти непосредственно к строке, которую хотите, а затем цикл "до конца".

Итак, ваш запрос будет таким:

SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
    FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0

Ответ 16

Самый простой способ был бы

SELECT * FROM table ORDER BY OrderColumn ASC LIMIT 50,25;

Это работает в MySQL и (я думаю) в других базах данных SQL.