Используя Linq к SQL, как я нахожу минуту и макс. столбца в таблице?

Я хочу найти самый быстрый способ получить минуту и макс. столбца в таблице с единственным 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, я думаю, что должен отметить его, как один отвечено. Мысли?

27
задан Community 23 May 2017 в 12:10
поделиться

5 ответов

Как указано в вопросе, этот метод, похоже, действительно генерирует оптимальный код 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)  
} 
31
ответ дан 28 November 2019 в 05:26
поделиться

Я смог найти только тот, который производит несколько чистый 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) )

или хранимая процедура ..

6
ответ дан 28 November 2019 в 05:26
поделиться

Вы можете выбрать всю таблицу и выполнять минимальные и максимальные операции в памяти:

var cache = // select *

var min = cache.Min(...);
var max = cache.Max(...);

В зависимости от размера вашего набора данных это может быть способ не попадать в базу данных более одного раза.

0
ответ дан 28 November 2019 в 05:26
поделиться

Запрос LINQ to SQL - это одно выражение. Таким образом, если вы не можете выразить свой запрос в одном выражении (или вам он не нравится, когда вы это сделаете), вам нужно рассмотреть другие варианты.

Хранимые процедуры, поскольку они могут иметь операторы, позволяют выполнить это за один проход. У вас будет либо два выходных параметра, либо набор результатов с двумя строками. В любом случае вам понадобится специальный код для чтения результата хранимой процедуры.

(Я лично не вижу необходимости здесь избегать двух циклов и обратно. Это кажется преждевременной оптимизацией, тем более что вам, вероятно, придется перепрыгивать через обручи, чтобы заставить ее работать. Не говоря уже о времени, которое вы потратите обосновывая это решение и объясняя решение другим разработчикам.)

Другими словами: вы уже ответили на свой вопрос. «Я не могу использовать .Min без предварительной группировки», за которым следует «это сумасшедшее предложение о группе кажется глупым, а SQL, который он создает, более сложен, чем должен быть», - это подсказки того, что простые и понятные два - двустороннее решение - лучшее выражение вашего намерения (если вы не пишете собственный SQL).

1
ответ дан 28 November 2019 в 05:26
поделиться

Я еще не уверен, как перевести его на 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 каким-то образом (я думаю).

2
ответ дан 28 November 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: