LINQ to SQL Каждый N-й ряд из таблицы
Кто-нибудь знает, как написать инструкцию LINQ to SQL, чтобы возвращать каждую n-ю строку из таблицы? Мне нужно получить заголовок элемента вверху каждой страницы в сетке с постраничной сетью для быстрого сканирования пользователей. Поэтому, если мне нужна первая запись, то каждый третий после этого, из следующих имен:
Эми, Эрик, Джейсон, Джо, Джон, Джош, Марибель, Пол, Стив, Том
Я бы получил Эми, Джо, Марибель и Том.
Я подозреваю, что это может быть сделано... Операторы LINQ to SQL уже вызывают функцию ROW_NUMBER() SQL в сочетании с сортировкой и подкачкой. Я просто не знаю, как вернуть каждый n-й предмет. Заявление SQL будет выглядеть как WHERE ROW_NUMBER MOD 3 = 0
, но я не знаю, какой оператор LINQ использовать для получения правильного SQL.
Ответы
Ответ 1
Иногда TSQL - это путь. Я бы использовал ExecuteQuery<T>
здесь:
var data = db.ExecuteQuery<SomeObjectType>(@"
SELECT * FROM
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS [__row]
FROM [YourTable]) x WHERE (x.__row % 25) = 1");
Вы также можете поменять n
:
var data = db.ExecuteQuery<SomeObjectType>(@"
DECLARE @n int = 2
SELECT * FROM
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS [__row]
FROM [YourTable]) x WHERE (x.__row % @n) = 1", n);
Ответ 2
Когда-то было не так, как Row_Number, и все же такие запросы были возможны. Вот!
var query =
from c in db.Customers
let i = (
from c2 in db.Customers
where c2.ID < c.ID
select c2).Count()
where i%3 == 0
select c;
Это порождает следующие Sql
SELECT [t2].[ID], [t2]. --(more fields)
FROM (
SELECT [t0].[ID], [t0]. --(more fields)
(
SELECT COUNT(*)
FROM [dbo].[Customer] AS [t1]
WHERE [t1].[ID] < [t0].[ID]
) AS [value]
FROM [dbo].[Customer] AS [t0]
) AS [t2]
WHERE ([t2].[value] % @p0) = @p1
Ответ 3
Здесь вариант, который работает, но, возможно, стоит проверить, что на практике он не имеет проблем с производительностью:
var nth = 3;
var ids = Table
.Select(x => x.Id)
.ToArray()
.Where((x, n) => n % nth == 0)
.ToArray();
var nthRecords = Table
.Where(x => ids.Contains(x.Id));
Ответ 4
На самом деле нет простого способа сделать это:
Как добавить ROW_NUMBER в запрос LINQ или Entity?
Как найти ROW_NUMBER() строки с Linq to SQL
Но всегда:
peopleToFilter.AsEnumerable().Where((x,i) => i % AmountToSkipBy == 0)
ПРИМЕЧАНИЕ: Это все еще не выполняется на стороне базы данных!
Ответ 5
Просто поиграть по-разному немного не нашел (или испытал) вариант для Linq to SQL, чтобы напрямую поддерживать это.
Единственный вариант, который я могу предложить, - это написать хранимую процедуру с выписанным SQL-запросом и затем вызвать sproc через Linq to SQL. Не лучшее решение, особенно если у вас есть какая-то сложная фильтрация.
Ответ 6
Это сделает трюк, но это не самый эффективный запрос в мире:
var count = query.Count();
var pageSize = 10;
var pageTops = query.Take(1);
for(int i = pageSize; i < count; i += pageSize)
{
pageTops = pageTops.Concat(query.Skip(i - (i % pageSize)).Take(1));
}
return pageTops;
Он динамически строит запрос, чтобы вытащить значение (nth, 2 * nth, 3 * nth и т.д.) из данного запроса. Если вы используете эту технику, вы, вероятно, захотите создать лимит, возможно, десяти или двадцати имен, аналогичный тому, как страница результатов Google (1-10 и далее), чтобы избежать получения столь большого выражения, которое база данных отказывается попытайтесь разобрать его.
Если вам нужна более высокая производительность, вам, вероятно, придется использовать хранимую процедуру или представление для представления вашего запроса и включить номер строки как часть сохраненных результатов процесса или полей представления.