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

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

124 голосов
/ 09 октября 2008

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

SELECT * FROM MyTable OFFSET 50 LIMIT 25

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

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

Ответы [ 16 ]

150 голосов
/ 09 октября 2008

Я бы не стал использовать 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

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

95 голосов
/ 03 апреля 2011

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

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

22 голосов
/ 09 октября 2008

Это один из способов (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
10 голосов
/ 09 октября 2008

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

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20
6 голосов
/ 12 мая 2014

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

6 голосов
/ 25 октября 2012

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

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 должна просматривать только один столбец, и только совпадающие строки возвращаются со всеми столбцами.

5 голосов
/ 23 декабря 2013

см. Мой выбор для 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

Это решает нумерацию страниц;)

3 голосов
/ 21 мая 2014
SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable
2 голосов
/ 07 мая 2015

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

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

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

2 голосов
/ 27 ноября 2009

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

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

DECLARE @ROWCOUNT INT = @Offset+@Limit
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...