Я хочу найти самый быстрый способ получить минуту и макс. столбца в таблице с единственным Linq к распространению в прямом и обратном направлениях SQL. Таким образом, я знаю, что это работало бы в двух распространениях в прямом и обратном направлениях:
int min = MyTable.Min(row => row.FavoriteNumber);
int max = MyTable.Max(row => row.FavoriteNumber);
Я знаю, что могу использовать group
но у меня нет a group by
пункт, я хочу агрегироваться по целой таблице! И я не могу использовать.Min, не группируясь сначала. Я действительно пробовал это:
from row in MyTable
group row by true into r
select new {
min = r.Min(z => z.FavoriteNumber),
max = r.Max(z => z.FavoriteNumber)
}
Но то, что сумасшедший пункт группы кажется глупым, и SQL, который он делает, более сложно, чем это должно быть.
Так, есть ли какой-либо способ просто вывести корректный SQL?
Править: Эти парни перестали работать также: Linq к SQL: как агрегироваться без группы?... хромой контроль разработчиками LINQ, если нет действительно никакого ответа.
РЕДАКТИРОВАНИЕ 2: Я посмотрел на свое собственное решение (с бессмысленной постоянной группой пунктом) в анализе плана выполнения Studio управления SQL Server, и это смотрит на меня как он, идентично плану, сгенерированному:
SELECT MIN(FavoriteNumber), MAX(FavoriteNumber)
FROM MyTable
таким образом, если кто-то не может придумать ответ simpler-or-equally-as-good, я думаю, что должен отметить его, как один отвечено. Мысли?
Как указано в вопросе, этот метод, похоже, действительно генерирует оптимальный код SQL , поэтому, хотя в LINQ это выглядит немного неуклюже, оно должно быть оптимальным с точки зрения производительности.
from row in MyTable
group row by true into r
select new {
min = r.Min(z => z.FavoriteNumber),
max = r.Max(z => z.FavoriteNumber)
}
Я смог найти только тот, который производит несколько чистый sql, все еще не очень эффективный по сравнению с выбором min (val), max (val) из таблицы:
var r =
(from min in items.OrderBy(i => i.Value)
from max in items.OrderByDescending(i => i.Value)
select new {min, max}).First();
sql равен
SELECT TOP (1)
[t0].[Value],
[t1].[Value] AS [Value2]
FROM
[TestTable] AS [t0],
[TestTable] AS [t1]
ORDER BY
[t0].[Value],
[t1].[Value] DESC
, но есть еще один вариант использования single соединение для минимальных и максимальных запросов (см. Несколько активных наборов результатов (MARS) )
или хранимая процедура ..
Вы можете выбрать всю таблицу и выполнять минимальные и максимальные операции в памяти:
var cache = // select *
var min = cache.Min(...);
var max = cache.Max(...);
В зависимости от размера вашего набора данных это может быть способ не попадать в базу данных более одного раза.
Запрос LINQ to SQL - это одно выражение. Таким образом, если вы не можете выразить свой запрос в одном выражении (или вам он не нравится, когда вы это сделаете), вам нужно рассмотреть другие варианты.
Хранимые процедуры, поскольку они могут иметь операторы, позволяют выполнить это за один проход. У вас будет либо два выходных параметра, либо набор результатов с двумя строками. В любом случае вам понадобится специальный код для чтения результата хранимой процедуры.
(Я лично не вижу необходимости здесь избегать двух циклов и обратно. Это кажется преждевременной оптимизацией, тем более что вам, вероятно, придется перепрыгивать через обручи, чтобы заставить ее работать. Не говоря уже о времени, которое вы потратите обосновывая это решение и объясняя решение другим разработчикам.)
Другими словами: вы уже ответили на свой вопрос. «Я не могу использовать .Min без предварительной группировки», за которым следует «это сумасшедшее предложение о группе кажется глупым, а SQL, который он создает, более сложен, чем должен быть», - это подсказки того, что простые и понятные два - двустороннее решение - лучшее выражение вашего намерения (если вы не пишете собственный SQL).
Я еще не уверен, как перевести его на C # (я работаю над этим)
Это версия Haskell
minAndMax :: Ord a => [a] -> (a,a)
minAndMax [x] = (x,x)
minAndMax (x:xs) = (min a x, max b x)
where (a,b) = minAndMax xs
Версия C # должна включить Aggregate
каким-то образом (я думаю).