Як написати LINQ's .Skip (1000) .Take (100) у чистому SQL?


93

Що таке еквівалент SQL .Skip()методу в LINQ?

Наприклад: Я хотів би вибрати рядки 1000-1100 з певної таблиці бази даних.

Чи можливо це лише за допомогою SQL? Або мені потрібно виділити всю таблицю, а потім знайти рядки в пам'яті? Я в ідеалі хотів би цього уникати, якщо це можливо, оскільки стіл може бути досить великим.

Відповіді:


78

У SQL Server 2005 і вище ви можете використовувати функцію ROW_NUMBER . напр.

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 51 AND 60; --BETWEEN is inclusive

Перегляньте посилання в моїй відповіді, щоб дізнатись трохи докладніше. stackoverflow.com/questions/1744802/…
Майк Атлас,

МІЖ 51 та 60 - це включно.
Дрю Міллер

1
Але це спочатку виділить все, а потім з цього виділення візьме лише 10, так? Або перший запит / подання вже матиме лише 10?
Тадей

139

SQL Server 2012 і вище додали такий синтаксис:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY

11
Зверніть увагу, що вам потрібно використовувати ORDER BY ___ для того, щоб використовувати команду OFFSET .... не те, що ви коли-небудь повинні пробувати перенесення сторінок без замовлення.
James Haug

Також зверніть увагу, що в «новому» синтаксисі дивним чином є покарання за продуктивність, лінійне з @skip! Підхід row_number цього НЕ має (протестовано лише в індексованому порядку). Для lo @Skip менше приблизно 20, новий синтаксис швидший, ніж підхід row_number.
Еске Ран,

22

LINQ to SQL робить це за допомогою функції вікна ROW_NUMBER:

  SELECT a,b,c FROM 
   (SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
    FROM Table) t0
   WHERE to.row_number BETWEEN 1000 and 1100;

Це працює, але необхідність виготовити номер_ рядка з ORDER BY може призвести до того, що ваш запит буде відсортований на стороні сервера і спричинить проблеми з продуктивністю. Навіть коли індекс може задовольнити вимогу ORDER BY, запит все одно повинен нарахувати 1000 рядків перед початком повернення результатів. Занадто часто розробники забувають про це і просто кидають елемент керування пагінацією над таблицею 5 мільйонів рядків і дивуються, чому перша сторінка повертається набагато швидше, ніж остання ...

Тим не менш, використання ROW_NUMBER () - це, мабуть, найкращий баланс між простотою використання та гарною продуктивністю, за умови, що ви уникаєте сортування (умова ORDER BY може бути задоволено індексом).


1
Дякуємо за додаткову інформацію про ефективність, доведеться бути обережним і протестувати її.
Рей

Перевірено і для моєї таблиці рядків у півмільйона ця остання сторінка приблизно в 7 разів повільніша за першу сторінку. Не ідеально, але прийнятно для мене.
Рей

6

Спробуйте це:

select * from [Table-Name] order by [Column-Name] 
offset [Skip-Count] rows
FETCH NEXT [Take-Count] rows only

Приклад:

select * from Personals order by Id
offset 10 rows            --------->Skip 10
FETCH NEXT 15 rows only   --------->Take 15

4

Зробити це:

Запустіть .Skip (1000). Візьміть (100) на LINQ to SQL datacontext і перегляньте вихідні дані SQL. Він створить для вас оператор SQL, який виконує те, що ви описуєте.

Це буде не так елегантно, але це робить роботу.


2
Не те, про що просили.
RayLoveless

2

Ні, але ви можете емулювати речення MySQL LIMIT (посилання на переповнення стека), щоб досягти того самого результату.


1
Там прийнята відповідь вказує на цікаве посилання CodeProject, "Підкачування великих наборів результатів у ASP.NET" (більше орієнтоване на SQL, ніж випливає з назви).
jorffin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.