получить определенный диапазон строк в таблице SQL Server

У меня есть структура таблицы, такая как (OrderID [uniqueidentifier], OrderDesciption [nvarchar]), я использую ADO.Net + C# + VSTS 2008 + SQL Server 2008. Таблица большая, и я хочу, чтобы клиент дал мне два входа, индекс начального диапазона и индекс конечного диапазона, и я верну определенные строки таблицы, которая находится в диапазоне (между индексом начального диапазона и индексом конечного диапазона).

Например, если клиент вводит мне 50, 100, и я хочу вернуть 50-ю строку до 100-й строки.

заранее спасибо, Джордж


person George2    schedule 21.06.2009    source источник


Ответы (4)


Вы можете использовать ROW_NUMBER в TSQL (начиная с 2005 г.), чтобы сделать это:

SELECT  ID, Foo, Bar
FROM     (SELECT  ROW_NUMBER() OVER (ORDER BY ID ASC) AS Row,
          ID, Foo, Bar
FROM    SomeTable) tmp
WHERE   Row >= 50 AND Row <= 100

Или с LINQ-to-SQL и т. д.:

var qry = ctx.Table.Skip(50).Take(50); // or similar
person Marc Gravell    schedule 21.06.2009
comment
Что-то не так выводится из студии управления SQL Server. Я попробовал ваше выражение SQL таким образом, выберите [OrderStatus].[OrderID], [OrderStatus].[OrderStatus] из (SELECT ROW_NUMBER() OVER (ORDER BY Date DESC) AS Row, [OrderStatus].[OrderID], [ OrderStatus].[OrderStatus] from [OrderStatus]), где Row ›= 0 и Row ‹ 100 Сообщение об ошибке, Msg 156, уровень 15, состояние 1, строка 5 Неверный синтаксис рядом с ключевым словом «где». - person George2; 21.06.2009
comment
Где твое исправление? Я запутался. Не могли бы вы указать это, пожалуйста? :-) - person George2; 21.06.2009
comment
Я добавил новый столбец с именем OrderCreateTime, и я думаю, что если мы SELECT xxx, ROW_NUMBER() OVER (ORDER BY OrderCreateTime) должен быть лучше, чем порядок по идентификатору заказа, верно? И почему? - person George2; 21.06.2009
comment
температура? Я не увидел в вашем текущем посте термин, называемый tmp? Смущенный. :-) - person George2; 21.06.2009
comment
Если OrderID является столбцом IDENTITY, он, скорее всего, будет увеличиваться со временем и является более простым типом данных. Конечно, если у вас есть кластеризованный индекс в OrderCreateTime, то он идеален для упорядочивания... - person Marc Gravell; 21.06.2009
comment
см. FROM SomeTable) tmp — этот псевдоним — все, что требуется для его работы. - person Marc Gravell; 21.06.2009
comment
Спасибо, Марк, так как OrderID — это GUID, и это уже кластеризованный индекс (поскольку клиенты будут часто запрашивать информацию о заказе по идентификатору заказа), поэтому вы считаете, что создание обычного индекса для OrderCreateTime является приемлемым решением? - person George2; 21.06.2009
comment
Guid обычно создает очень плохой кластеризованный индекс (но отличный некластеризованный индекс). Используете ли вы расчесывание для создания увеличивающихся направляющих? Если нет, я бы рекомендовал переключить кластеризованный индекс на OrderCreateTime. Некластеризованный индекс также хорош для сортировки, но просто не настолько хорош, поэтому, если необходимо, подойдет некластеризованный индекс для OrderCreateTime, но вы редко выполняете сопоставление на равенство для вещей, которые включают время, поэтому обычно время делает плохой некластеризованный индекс. - person Marc Gravell; 21.06.2009
comment
Можно ли заказать такой стол? Я создал таблицу, которая содержит столбец DateTime, и я хочу сделать заказ в этом столбце, но, видимо, он игнорирует ORDER BY. - person thomasvdb; 26.04.2011
comment
Это мой запрос, но он не упорядочивает его [дата события]: ВЫБЕРИТЕ [ID], [операция], [причина], [дата события] ОТ (ВЫБЕРИТЕ ROW_NUMBER() НАД (ЗАКАЗАТЬ ПО ИДЕНТИФИКАТОРу ASC) КАК Строка, [ID ] ,[операция] ,[причина] ,[дата события] FROM myTable ) tmp WHERE Row ›= @rowFrom AND Row ‹ @rowTo ORDER BY eventdate DESC; - person thomasvdb; 27.04.2011
comment
@thomasvdb посмотри на OVER (ORDER BY ID ASC)... видимо тебе нужно это настроить? - person Marc Gravell; 27.04.2011
comment
У кого-нибудь есть статистика о том, какое решение более эффективно, это или то, что опубликовал @marc_s? - person Mason G. Zhwiti; 07.10.2011
comment
@MasonG.Zhwiti, если вы имеете в виду сравнение двух версий SQL, то у них идентичные планы запросов; они выполняют то же самое - person Marc Gravell; 07.10.2011

По сути, лучше всего в SQL Server 2005 и 2008 использовать CTE — Common Table Expression — с функцией ROW_NUMBER() — что-то вроде этого:

WITH MyOrders AS
(
  SELECT
    OrderID,
    OrderDescription,
    ROW_NUMBER() OVER (ORDER BY OrderID) as 'RowNum'
  FROM YourOrders
)
SELECT * FROM MyOrders
WHERE RowNum BETWEEN 50 AND 100

Но для этого требуется полезное и подходящее предложение ORDER BY, а упорядочивание по GUID — не очень хорошая идея. Лучше всего использовать DATETIME или постоянно увеличивающийся идентификатор.

Марк

person marc_s    schedule 21.06.2009
comment
Привет, Марк, извините за мое плохое описание, я не хочу, чтобы клиент указывал диапазон по значению GUID orderID, но указывал диапазон по физическому номеру строки таблицы. Есть идеи, как это реализовать? - person George2; 21.06.2009
comment
Что ж, мой CTE выше в моем посте делает это - просто выбор по GUID - очень плохой способ упорядочивания ваших данных - в основном это совершенно случайно...... но если это то, что вы ищете, мой фрагмент кода должен достичь этого. - person marc_s; 21.06.2009
comment
Запутался в этом утверждении -- ROW_NUMBER() OVER (ORDER BY OrderID) as 'RowNum' -- поскольку orderID является случайным GUID, я хочу получить диапазон по физическому диапазону строк в таблице базы данных, а не по диапазону значений идентификатора заказа. Похоже, что в приведенном мной утверждении вы выбираете диапазон строк по идентификатору заказа? - person George2; 21.06.2009
comment
Я согласен, Марк, но в вашем заявлении есть ошибка при выполнении в студии управления SQL Server, я опубликовал сообщение об ошибке выполнения и вывода кода SQL, что не так? - person George2; 21.06.2009
comment
Я добавил новый столбец с именем OrderCreateTime, и я думаю, что если мы SELECT xxx, ROW_NUMBER() OVER (ORDER BY OrderCreateTime) должен быть лучше, чем порядок по идентификатору заказа, верно? И почему? - person George2; 21.06.2009
comment
@George2: да, выбор по OrderCreateTime был бы намного лучше - поскольку он определяет реальный заказ - по дате/времени создания заказа. GUID для идентификатора заказа — это просто случайное число, которое на самом деле не имеет характеристики порядка. - person marc_s; 21.06.2009
comment
Функция ROW_NUMBER() должна быть определена поверх определения порядка. Только когда вы поместите все свои строки в ЗАКАЗ (любого типа), только тогда вы сможете прикрепить к ним ROW_NUMBER. Набор строк SQL Server сам по себе не имеет порядка, поэтому вам нужно определить порядок, выполнив OVER (ORDER BY (имя столбца)) для того, чтобы функция ROW_NUMBER знала, как прикреплять номера строк к строкам. - person marc_s; 21.06.2009
comment
Поскольку OrderID — это GUID, и это уже кластеризованный индекс (поскольку клиенты будут часто запрашивать информацию о заказе по идентификатору заказа), то считаете ли вы создание обычного индекса для OrderCreateTime приемлемым решением? - person George2; 21.06.2009
comment
Спасибо! Еще один вопрос: как вы думаете, лучше использовать CTE для моего сценария или лучше использовать простой T-SQL, как предлагает Kiewic? И почему? - person George2; 21.06.2009
comment
Я могу только поддержать рекомендацию Марка Гравелла: GUID очень плохо работает с CLUSTERED index — было бы НАМНОГО ЛУЧШЕ иметь OrderID INT IDENTITY и поместить CLUSTERED Index в этот столбец. - person marc_s; 21.06.2009
comment
В конце концов, план выполнения запроса Кевика и моего идентичны. Я предпочитаю КТЭ - он мне кажется более понятным - но это субъективное, личное мнение. - person marc_s; 21.06.2009

Попробуйте это, результат будет упорядочен по столбцу OrderID. Замените MyTable своей таблицей.

SELECT * 
FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY OrderID) AS row FROM MyTable) a 
WHERE row > 50 AND row <= 100

Выбраны строки от 50 до 100, но обратите внимание, что 50-я строка не включена в результат.

person kiewic    schedule 21.06.2009
comment
Я выполняю ваше заявление, но что-то из SQL Server Management Studio. выберите * из (SELECT ROW_NUMBER() OVER (ORDER BY [OrderStatus].[OrderID]) AS Row from [OrderStatus]), где Row ›= 0 и Row ‹ 100 Сообщение об ошибке, Msg 156, уровень 15, состояние 1, строка 4 Неправильный синтаксис рядом с ключевым словом «где». - person George2; 21.06.2009
comment
Эй, вы сотрите букву a, которая была после SELECT в третьей строке. Это псевдоним, и это необходимо. - person kiewic; 21.06.2009
comment
Я добавил новый столбец с именем OrderCreateTime, и я думаю, что если мы SELECT *, ROW_NUMBER() OVER (ORDER BY OrderCreateTime) должен быть лучше, чем порядок по заказу по идентификатору заказа, правильно и почему? - person George2; 21.06.2009
comment
a дает имя анонимному запросу в скобках. - person kiewic; 22.06.2009
comment
Извините, как я могу сделать это в MYSQL SELECT. Спасибо - person LTEHUB; 12.07.2012
comment
@maydenec Это эквивалентно SELECT * FROM MyTable LIMIT 50, 50 в MySQL. - person kiewic; 12.07.2012

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY OrderId) as row FROM Orders) a WHERE row > 5 and row ‹= 10

person balint    schedule 21.06.2009
comment
Я попробовал ваше решение, но что-то не так, SELECT * FROM [dbo].[OrderStatus] (SELECT *, ROW_NUMBER() OVER (ORDER BY [OrderID]) as row FROM [dbo].[OrderStatus]), где строка › 0 и строка ‹ 100 Сообщения об ошибках: сообщение 156, уровень 15, состояние 1, строка 2. Неверный синтаксис рядом с ключевым словом «SELECT». Сообщение 102, уровень 15, состояние 1, строка 2 Неверный синтаксис рядом с ')'. - person George2; 21.06.2009
comment
Я добавил новый столбец с именем OrderCreateTime, и я думаю, что если мы SELECT xxx, ROW_NUMBER() OVER (ORDER BY OrderCreateTime) должен быть лучше, чем порядок по идентификатору заказа, верно? И почему? - person George2; 21.06.2009
comment
вы пропустили название select .. from Orders) ››a‹‹ где.. - person balint; 21.06.2009