Возвращает строки между определенным диапазоном, с одним выражением select
Я ищу некоторые выражения вроде этого (с использованием SQL Server 2008)
SELECT TOP 10 columName FROM tableName
Но вместо этого мне нужны значения от 10 до 20. И мне интересно, есть ли способ сделать это, используя только один оператор SELECT.
Например, это бесполезно:
SELECT columName FROM
(SELECT ROW_NUMBER() OVER(ORDER BY someId) AS RowNum, * FROM tableName) AS alias
WHERE RowNum BETWEEN 10 AND 20
Потому что выбор внутри скобок уже возвращает все результаты, и я хочу избежать этого из-за производительности.
Ответы
Ответ 1
Существует трюк с row_number
, который не включает сортировку всех строк.
Попробуйте следующее:
SELECT columName
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (select NULL as noorder)) AS RowNum, *
FROM tableName
) as alias
WHERE RowNum BETWEEN 10 AND 20
Вы не можете использовать константу в order by
. Однако вы можете использовать выражение, которое оценивается константой. SQL Server распознает это и просто возвращает строки как встречающиеся, правильно перечисленные.
Ответ 2
Почему, по вашему мнению, SQL Server будет оценивать весь внутренний запрос? Предполагая, что ваш столбец сортировки проиндексирован, он будет просто читать первые 20 значений. Если вы действительно нервничаете, вы можете это сделать:
Select
Id
From (
Select Top 20 -- note top 20
Row_Number() Over(Order By Id) As RowNum,
Id
From
dbo.Test
Order By
Id
) As alias
Where
RowNum Between 10 And 20
Order By
Id
но я уверен, что план запросов одинаковый.
(Действительно) Исправлено в соответствии с комментарием Aaron.
http://sqlfiddle.com/#!3/db162/6
Ответ 3
Использовать SQL Server 2012 для извлечения/пропуска!
SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty, UnitPrice, LineTotal
FROM AdventureWorks2012.Sales.SalesOrderDetail
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Там ничего лучше, чем вы описываете для более старых версий sql-сервера. Может быть, использовать CTE, но вряд ли изменит ситуацию.
WITH NumberedMyTable AS
(
SELECT
Id,
Value,
ROW_NUMBER() OVER (ORDER BY Id) AS RowNumber
FROM
MyTable
)
SELECT
Id,
Value
FROM
NumberedMyTable
WHERE
RowNumber BETWEEN @From AND @To
или вы можете удалить первые 10 строк, а затем получить следующие 10 строк, но я бы удвоил, кто захочет это сделать.
Ответ 4
Еще один вариант
SELECT TOP(11) columName
FROM dbo.tableName
ORDER BY
CASE WHEN ROW_NUMBER() OVER (ORDER BY someId) BETWEEN 10 AND 20
THEN ROW_NUMBER() OVER (ORDER BY someId) ELSE NULL END DESC
Ответ 5
Вы можете создать временную таблицу, которая упорядочена так, как вы хотите:
SELECT ROW_NUMBER() OVER (ORDER BY someId) AS RowNum, * FROM tableName
в ## tempTable
...
Таким образом, у вас есть упорядоченный список строк.
и может просто запрашивать по номеру строки последующие времена, а не выполнять внутренний запрос несколько раз.