Смещение строки в 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.