Як реалізувати LIMIT за допомогою SQL Server?


130

У мене є цей запит у MySQL:

select * from table1 LIMIT 10,20

Як я можу це зробити за допомогою SQL Server?


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

13
Оскільки це питання було задано першим, чи не було б інше питання повторюваним?
— Tab Alleman

Відповіді:


127

Починаючи 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
2-й запит не вдається, якщо у таблиці є, наприклад, 14 рядків. Він дає вам рядки від 5 до 14, але ви хочете, щоб рядки були від 11 до 14. Загалом, це не вдається для останньої "сторінки" результату, якщо тільки загальні рядки не кратні тому розміру "сторінки".
— Білл Карвін

147
Таку просту річ потрібно ще раз зробити так важкою для MS!
— Мартін

Ось що для мене працювало в SQL Server Management Studio 2017: SELECT * FROM [dbo]. <Insert the nameName here> WHERE @@ ROWCOUNT BETWEEN <insert min here> and <insert max here>
— Artorias2718

Просто фантастично, це працює як шарм у програмі MS SQL Server 2017 select select
— 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 є злочинним, IMO. Вам не слід було б робити подібні хитрі рішення.


Чи є у вас ще одна пропозиція обійти це?
— Бігболи

Я багато робив у Google, коли в останній раз доводилося стикатися з MSSQL, і це було найкращим рішенням, яке я знайшов. Не приємно, але це працює.
— ceejayoz

Це рішення працює лише в тому випадку, якщо набір результатів містить унікальний стовпець. Це не загальне рішення для імітації LIMIT для будь-якого запиту.
— Білл Карвін

1
Я зараз в подібній скруті ... Проте, в моєму випадку мене вдягнули ... Це ще більш кримінально, коли так званий "експерт" dba вирішив, що унікальний ключ непотрібний у таблиці ... БУДЬ-яка таблиця ... Навіть не пред'являйте тему сторонніх ключів і обмежень!
— Ендрю Роллінгз

Проблема в цьому полягає в тому, що він не дуже добре справляється з пунктами WHERE ... Я спробую виправити таблиці temp, оскільки для мене це не працює.
— бридкий пастоз

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, повернутий набір результатів не є таким, як очікувалося.


Для використання запиту "з" потрібно лише половину часу, щоб закінчити запит - дивіться відповідь @Leon Tayson. Я поняття не маю, що Microsoft зробив, щоб зробити це так повільно.
— isHuman

1
Чому це не прийнята відповідь? Ми в 2018 році плачемо вголос!
— Шкіпер

1
@Skipper справа. прийнятий досі працює. Давайте просто підкреслимо це, щоб відобразити оновлення.
— крон

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

@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

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

Якщо поля додані чи видалені, "рядок" оновлюється автоматично.

Основна проблема цього варіанту полягає в тому, що ЗАМОВЛЕННЯ ВИМОГА. Тож якщо ви хочете іншого порядку, вам доведеться створити інший вигляд.

ОНОВЛЕННЯ

З цим підходом є ще одна проблема: якщо ви спробуєте відфільтрувати свої дані, він не працюватиме, як очікувалося. Наприклад, якщо ви робите:

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

ЧИМО обмежується тими даними, які знаходяться в рядках між 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;

Було чудовим рішенням для мене.
— Тайд

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

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

ЗАМОВЛЕННЯ ОБОВ'ЯЗКОВО


-2

Якщо я правильно пам’ятаю (минуло деякий час, коли я зайнявся програмою SQL Server), можливо, ви зможете використовувати щось подібне: (2005 р. І вище)

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

SQL Server 2012: Msg 207, рівень 16, стан 1, рядок 5 Недійсна назва стовпця "RowNum".
— e-info128

звучить так, що у вас десь є помилка друку. RowNum - це ім'я, яке ми присвоюємо виразу. Опублікуйте свою проблему з джерелом, і громада допоможе вам
— Крис,

Це невірний синтаксис. Ви не можете посилатися WHEREна псевдонім, визначений у тому самому рівні SELECT.
— ypercubeᵀᴹ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.