Выберите подмножество строк с помощью Row_Number ()

Select id, name, ROW_NUMBER() OVER (ORDER BY id asc) as 'RowNo'
from customers
where RowNo between 50 AND 60

Я пытаюсь выбрать подмножество строк от 50 до 60. Проблема в том, что "RowNo" - недопустимое имя столбца.

Спасибо

Использование SQL SERVER 2008 R2


person test    schedule 17.02.2012    source источник
comment
Пожалуйста, не используйте 'string delimiters' для псевдонимов. Этот синтаксис нестандартен, может сбивать с толку (например, SELECT 'a' 'b') и не рекомендуется в SQL Server. Используйте [square brackets] (также нестандартный) или "double quotes" (стандартный) или без разделителей. Для получения дополнительной информации и множества дискуссий см. sqlblog.com/blogs/aaron_bertrand/archive/2012/01/23/   -  person Aaron Bertrand    schedule 17.02.2012
comment
P.S. споры ведутся о том, что вам следует использовать. Есть небольшой аргумент в пользу того, что одинарные кавычки не следует использовать.   -  person Aaron Bertrand    schedule 17.02.2012
comment
@Aaron: спасибо, я не был уверен, устарело это или запрещено в последней версии.   -  person ypercubeᵀᴹ    schedule 17.02.2012
comment
@ypercube Он по-прежнему работает в текущих версиях, но вызывает устаревшие предупреждающие события (trace / perfmon). Что ж, только определенные формы вызывают устаревшие события, но это другая история.   -  person Aaron Bertrand    schedule 17.02.2012


Ответы (2)


Используйте свой запрос как подзапрос, как показано ниже:

select * from (
    Select id, name, ROW_NUMBER() OVER (ORDER BY id asc) as [RowNo]
    from customers
) t
where RowNo between 50 AND 60

Вы также можете использовать CTE, но следует ли выбирать одно вместо другого, читайте Разница между CTE и SubQuery? и проверьте план выполнения.

person Michał Powaga    schedule 17.02.2012
comment
Спасибо! Я не знаю, зачем вам выполнять такой сложный запрос, когда в mysql вы просто используете LIMIT 49, 10! не могли бы вы сказать мне, почему мы должны были написать "т"? - person test; 17.02.2012
comment
@test: Потому что в SQL-сервере нет LIMIT x OFFSET y, как в MySQL. В нем есть только TOP n, что совпадает с LIMIT n в MySQL. - person ypercubeᵀᴹ; 17.02.2012
comment
Но с имеющимися у него аналитическими функциями, такими как ROWN_NUMBER() и другие, вы можете делать гораздо более сложные вещи (которые действительно сложно сделать в MySQL). - person ypercubeᵀᴹ; 17.02.2012
comment
@test SQL Server 2012 реализует стандартный метод разбиения на страницы (_1 _ / _ 2_). Конечно, MySQL - это просто, но нестандартно. Я писал об этом здесь: sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/ - person Aaron Bertrand; 17.02.2012
comment
@test t - это псевдоним для подзапроса, без него вы получите сообщение об ошибке (вы можете попробовать). Подробнее об этом Неправильный синтаксис рядом с чем-либо, использующим подзапрос < / а>. - person Michał Powaga; 17.02.2012
comment
@Aaron: Да ладно, мне нравится, что SQL-сервер реализует (наконец-то!) Стандарт для FETCH n ROWS, но вы не можете утверждать, что какой-то другой SQL-продукт нестандартен, то есть не так хорош. TOP n тоже нестандартен, и многие пользователи SQL-Server не будут обновляться до версии 2012. - person ypercubeᵀᴹ; 17.02.2012
comment
@ypercube Я полностью сторонник проприетарных расширений языка, но если в стандарте что-то уже определено, я бы предпочел увидеть это реализованным, чем определять ваш собственный синтаксис. У меня много жалоб на ковбойский выбор SQL Server (например, TIMESTAMP), но в данном случае MySQL сделал это неправильно. - person Aaron Bertrand; 17.02.2012
comment
Я, конечно, согласен с этим. Но в MySQL это работало давным-давно. Не уверен, был ли синтаксис FETCH в стандарте в то время, когда вводились LIMIT и TOP. - person ypercubeᵀᴹ; 17.02.2012
comment
Что ж, TOP используется не только для разбиения по страницам, у него уже есть несколько вариантов использования. - person Aaron Bertrand; 17.02.2012

Вам нужно сделать что-то вроде этого:

;WITH PaginatingData AS
(
    Select id, name, ROW_NUMBER() OVER (ORDER BY id asc) as 'RowNo'
    from customers
)
SELECT *
FROM PaginatingData
where RowNo between 50 AND 60

Используйте CTE (Common Table Expression - своего рода «встроенное представление») в качестве «оболочки», чтобы ваш RowNo стал допустимым именем столбца.

В качестве перспективы - с SQL Server 2012 вы могли бы написать что-то вроде этого:

SELECT 
    id, name
FROM 
    dbo.customers
ORDER BY
    id
OFFSET 50 ROWS
FETCH NEXT 10 ROWS ONLY

SQL Server 2012 будет иметь нотацию, совместимую со стандартом ANSI SQL, чтобы выполнять разбиение по страницам напрямую на основе предложения ORDER BY. См. это сообщение в блоге (или множество других) для получения дополнительной информации и других примеров.

person marc_s    schedule 17.02.2012
comment
AS RowNo не нужны кавычки: 'RowNo', а? - person ypercubeᵀᴹ; 17.02.2012
comment
@ypercube Это не так, но это тоже не так. Это просто менее распространенный синтаксис T-SQL. - person Yuck; 17.02.2012
comment
@ypercube: Я не думаю, что это абсолютно необходимо - я просто оставил это, поскольку OP опубликовал его. Лично я бы использовал обозначение RowNo = ROW_NUMBER()....., но это просто личный стиль. - person marc_s; 17.02.2012
comment
@ypercube, yuck и marc, пожалуйста, посмотрите мой комментарий к вопросу (который я оставил до того, как увидел эти комментарии). Я понимаю, что Марк только что скопировал код OP, но, хотя синтаксис не является неправильным сегодня, он будет неправильным в будущей версии SQL Server. - person Aaron Bertrand; 17.02.2012