使用Linq to SQL,如何在表中找到列的最小值和最大值?

时间:2010-02-15 18:45:08

标签: c# sql linq-to-sql

我想找到一种最快的方法来获取表中的一个列的最小值和最大值,其中包含一个Linq to SQL往返。所以我知道这可以在两个往返中起作用:

int min = MyTable.Min(row => row.FavoriteNumber);
int max = MyTable.Max(row => row.FavoriteNumber);

我知道我可以使用group但是我没有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 to SQL: how to aggregate without a group by? ......如果没有答案,LINQ设计师会疏忽。

编辑2:我在SQL Server Management Studio执行计划分析中查看了我自己的解决方案(使用无意义的常量group by子句),它看起来像是与生成的计划相同:

SELECT MIN(FavoriteNumber), MAX(FavoriteNumber)
FROM MyTable

所以除非有人能提出一个更简单或同样好的答案,否则我认为我必须将其标记为自己回答。想法?

5 个答案:

答案 0 :(得分:29)

正如问题中所述,这种方法似乎实际上生成了最佳的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)  
} 

答案 1 :(得分:6)

我只能发现只有这个产生一些干净的sql仍然没有真正有效,相比于表中的select 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

还有另一个选项可以为最小和最大查询使用单一连接(请参阅Multiple Active Result Sets (MARS)

或存储过程..

答案 2 :(得分:2)

我不知道如何将其翻译成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一些(我认为)。

答案 3 :(得分:1)

LINQ to SQL查询是单个表达式。因此,如果您无法在单个表达式中表达您的查询(或者您不喜欢它),那么您必须查看其他选项。

存储过程,因为它们可以有语句,使您能够在一次往返中完成此操作。您将具有两个输出参数或选择具有两行的结果集。无论哪种方式,您都需要自定义代码来读取存储过程的结果。

(我个人认为没有必要避免在这里进行两次往返。这似乎是一种不成熟的优化,特别是因为你可能需要跳过篮球才能让它发挥作用。更不用说你花费的时间了证明这一决定并向其他开发商解释解决方案。)

换句话说:你已经回答了自己的问题。 “我不能在没有分组的情况下使用.Min”,接着是“疯狂的群组条款似乎很愚蠢,而且它制作的SQL比它需要的更复杂”,是简单易懂的两条线索 - 往返解决方案是您的意图的最佳表达(除非您编写自定义SQL)。

答案 4 :(得分:0)

您可以选择整个表格,并在内存中执行最小和最大操作:

var cache = // select *

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

根据数据集的大小,这可能是不多次访问数据库的方法。