Як реалізувати 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.