Как реализовать LIMIT с SQL Server?


130

У меня такой запрос с MySQL:

select * from table1 LIMIT 10,20

Как я могу сделать это с помощью SQL Server?


возможный дубликат LIMIT 10..20 в SQL Server
assylias

13
Поскольку этот вопрос был задан первым, не будет ли второй вопрос дубликатом?
Tab Alleman

Ответы:


128

Начиная с SQL SERVER 2005, вы можете сделать это ...

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 10 AND 20;

или что-то подобное для версий 2000 и ниже ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC

6
Второй запрос не выполняется, если у вас, например, 14 строк в таблице. Он дает вам строки с 5 по 14, но вам нужны строки с 11 по 14. Как правило, это не удается для последней «страницы» результата, если только общее количество строк не кратно размеру этой «страницы».
Билл Карвин,

147
MS должна снова сделать такую ​​простую вещь такой сложной!
Мартин

Вот что у меня сработало в SQL Server Management Studio 2017: SELECT * FROM [dbo]. <Insert tableName here> WHERE @@ ROWCOUNT BETWEEN <insert min here> and <insert max here>
Artorias2718

Просто фантастика, это работает как шарм в MS SQL Server 2017 select Statement
PatsonLeaner

58

Неуклюже, но это сработает.

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

Отсутствие MSSQL пункта LIMIT является преступлением, ИМО. Вам не нужно делать такого неуклюжего обходного пути.


У вас есть еще одно предложение, чтобы обойти это?
Bigballs, 02

В последний раз, когда мне приходилось иметь дело с MSSQL, я много гуглил, и это было лучшее решение, которое я нашел. Не очень приятно, но работает.
ceejayoz 02

Это решение работает, только если в результирующий набор входит уникальный столбец. Это не общее решение для имитации LIMIT для любого запроса.
Билл Карвин,

1
Я сейчас нахожусь в подобном затруднительном положении ... Однако в моем случае я в шоке ... Это еще более преступно, когда так называемые 'экспертные' базы данных решают, что уникальный ключ в таблице не нужен ... ЛЮБАЯ таблица ... Даже не поднимайте тему внешних ключей и ограничений!
Эндрю Роллингс,

Проблема с этим в том, что он не очень хорошо обрабатывает предложения WHERE ... Я собираюсь попробовать временные таблицы, так как это не работает для меня.
nasty pasty

37

Начиная с SQL SERVER 2012, вы можете использовать предложение OFFSET FETCH:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

Это может работать неправильно, если порядок по не уникален.

Если запрос изменен на ORDER BY OrderDate, возвращаемый набор результатов не соответствует ожидаемому.


Использование 'with' требует только половины времени для завершения запроса - см. Ответ @Leon Tayson. Я понятия не имею, что сделала Microsoft, чтобы сделать это так медленно.
isHuman 04

1
Почему это не принятый ответ? Мы в 2018 году за то, что громко кричали!
Skipper

1
@ Шкипер, верно. принятый еще работает. Давайте просто проголосуем за это, чтобы отразить обновление.
kronn 08

18

Это почти дубликат вопроса, который я задал в октябре: Эмуляция предложения MySQL LIMIT в Microsoft SQL Server 2000

Если вы используете Microsoft SQL Server 2000, хорошего решения нет. Большинству людей приходится прибегать к фиксации результата запроса во временной таблице с IDENTITYпервичным ключом. Затем запросите столбец первичного ключа, используя BETWEENусловие.

Если вы используете Microsoft SQL Server 2005 или более позднюю версию, у вас есть ROW_NUMBER()функция, поэтому вы можете получить тот же результат, но избегать временной таблицы.

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

Вы также можете написать это как общее выражение таблицы , как показано в @Leon Tayson в ответ .


ROW_NUMBER () OVER (ORDER BY) получает баллы за то, что он действителен в ANSI SQL: 2003, хотя поддержка в СУБД, отличных от SQL Server, очень нечеткая. И это, конечно, довольно неуклюже ...
bobince 02

@bobince: Оказывается, Oracle, Microsoft SQL Server 2005, IBM DB2 и PostgreSQL 8.4 поддерживают оконные функции. Это покрывает огромную часть рынка SQL. Поддержка частичная, только если вы используете MySQL, SQLite или старую версию БД, указанную выше.
Билл Карвин

16

Вот как я ограничиваю результаты в MS SQL Server 2012:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

ПРИМЕЧАНИЕ: OFFSETможет использоваться только с или в тандеме с ORDER BY.

Чтобы объяснить строку кода OFFSET xx ROWS FETCH NEXT yy ROW ONLY

Это номер xxзаписи / строки, из которой вы хотите начать извлечение в таблице, то есть: если в таблице 1 40 записей, приведенный выше код начнет извлекать из строки 10.

Это yyколичество записей / строк, которые вы хотите извлечь из таблицы.

Основываясь на предыдущем примере: если таблица 1 содержит 40 записей, и вы начали извлекать из строки 10 и взять СЛЕДУЮЩИЙ набор из 10 (yy ). Это будет означать, что приведенный выше код будет извлекать записи из таблицы 1, начиная со строки 10 и заканчивая 20. Таким образом, извлекаются строки 10-20.

Перейдите по ссылке для получения дополнительной информации о OFFSET


12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10

Хорошо, я только что проверил, SQL Server оказался достаточно умен, чтобы остановиться на условиях ROW_NUMBER (), если в предложении ORDER BY есть индексированный столбец.
Quassnoi 02

9

Синтаксически запрос MySQL LIMIT выглядит примерно так:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Это можно перевести на Microsoft SQL Server, например

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

Теперь ваш запрос select * from table1 LIMIT 10,20будет таким:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

2

Это одна из причин, по которой я стараюсь избегать использования MS Server ... но в любом случае. Иногда у вас просто нет возможности (ага! И мне нужно использовать устаревшую версию !!).

Мое предложение - создать виртуальную таблицу:

Из:

SELECT * FROM table

Для того, чтобы:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

Затем просто запросите:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Если поля добавляются или удаляются, «строка» обновляется автоматически.

Основная проблема с этой опцией в том, что ORDER BY исправлен. Поэтому, если вам нужен другой порядок, вам придется создать другое представление.

ОБНОВИТЬ

У этого подхода есть еще одна проблема: если вы попытаетесь отфильтровать данные, это не сработает так, как ожидалось. Например, если вы это сделаете:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

WHERE ограничивается теми данными, которые находятся в строках от 10 до 20 (вместо поиска всего набора данных и ограничения вывода).


1

Это многоэтапный подход, который будет работать в SQL2000.

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10

1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;

Было для меня отличным решением.
Тайд 08

1

Должен попытаться. В приведенном ниже запросе вы можете увидеть группировку, порядок, пропуск строк и ограничение строк.

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows

0
SELECT TOP 10 * FROM table;

Такой же как

SELECT * FROM table LIMIT 0,10;

Вот статья о реализации Limit в MsSQL. Ее приятно прочитать, особенно комментарии.


1
Спасибо, но я хочу, чтобы запись была между 10 и 20, есть способ сделать это?
Bigballs, 02

5
Этот ответ не отвечает на вопрос о происхождении, но он полезен, если кому-то вроде меня нужно знать, как получить первые N результатов и попасть сюда через Google и т. Д.
brianlmerritt

0

В SQL нет ключевого слова LIMIT. Если вам нужно только ограниченное количество строк, вы должны использовать ключевое слово TOP, подобное LIMIT.


0

Если ваш идентификатор является уникальным типом идентификатора или ваш идентификатор в таблице не отсортирован, вы должны сделать следующее.

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



Код будет

выберите * из лимита 2,5

0

лучше использовать это в MSSQLExpress 2017.

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

- Назначение столбца [Количество] и присвоение каждой строке уникального подсчета без какого-либо заказа, затем снова выберите, где вы можете указать свои пределы .. :)


0

Один из возможных способов получить результат, как показано ниже, надеюсь, это поможет.

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end

0

Простой способ

MYSQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY является обязательным


-2

Если я правильно помню (прошло некоторое время с тех пор, как я попробовал SQL Server), вы можете использовать что-то вроде этого: (2005 и новее)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

SQL Server 2012: сообщение 207, уровень 16, состояние 1, строка 5 Недопустимое имя столбца "RowNum".
e-info128,

звучит так, будто в вашем заявлении где-то есть опечатка RowNum - это имя, которое мы присваиваем выражению. Опубликуйте свою проблему с источником, и сообщество вам поможет
Крис

Это недопустимый синтаксис. Вы не можете ссылаться WHEREна псевдоним, определенный в том же SELECTпредложении уровня .
ypercubeᵀᴹ
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.