Max(x => x.Time)vs OrderByDescending(x => x.Time).First()。Time

时间:2011-03-09 02:02:11

标签: c# linq linqpad sqlexception

我提出了一个相关的问题:
'Invalid column name [ColumnName]' on a nested linq query

我正试图在这里问到一个小组的第一行:
Linq - Top value from each group

然而,我接近它与使用Max的接受答案不同。我是这样做的:

ATable
    .GroupBy (t => t.ID)
    .Select ( t => t.OrderByDescending(x=>x.Timestamp).FirstOrDefault().Timestamp)

这会导致错误SqlException: Invalid column name 'ID'

现在我使用Max功能:

ATable
    .GroupBy (t => t.ID)
    .Select ( t => t.Max(x=>x.Timestamp))

它返回我想要的时间列表。

我的理解是他们是不同的,但等效的电话。为什么我在第一次调用时遇到sql错误?

更新
为第一个查询生成的sql查询如下所示:

SELECT (
    SELECT [t3].[Timestamp]
    FROM (
        SELECT TOP 1 [t2].[Timestamp]
        FROM [ATable] AS [t2]
        WHERE (([t1].[ID] IS NULL) AND ([t2].[ID] IS NULL)) OR (([t1].[ID] IS NOT NULL) AND ([t2].[ID] IS NOT NULL) AND ([t1].[ID] = [t2].[ID]))
        ORDER BY [t2].[Timestamp] DESC
        ) AS [t3]
    ) AS [value]
FROM (
    SELECT [t0].[ID]
    FROM [ATable] AS [t0]
    GROUP BY [t0].[ID]
    ) AS [t1]

我设法减少它但保持相同的错误:

SELECT (
    SELECT [t3].[Timestamp]
    FROM (
        SELECT TOP 1 [Timestamp]
        FROM [ATable]
        WHERE [t1].[ID] = [ID]
        ) AS [t3]
    ) AS [value]
FROM (
    SELECT [ID]
    FROM [ATable]
    GROUP BY [ID]
    ) AS [t1]

UPDATE2
有些答案说这些查询在逻辑上是不同的,但是,如果你在northwind表上做这样的事情,它会产生相同的结果:

OrderDetails
    .GroupBy(x=>x.ProductID)
    .Select(x=>x.OrderByDescending(y=>y.UnitPrice).FirstOrDefault().UnitPrice).Dump();

OrderDetails
    .GroupBy(x=>x.ProductID)
    .Select(x=>x.Max(y=>y.UnitPrice)).Dump();

所以我不能接受3个答案中的任何一个,这些答案表示查询不同或者Max给出的是Sum而不是列表的最大值,或者你必须在继续之前将IQueriable转换为列表。

1 个答案:

答案 0 :(得分:4)

更新2 :我只想回复此问题:

  

然而,如果你做这样的事情   在北风桌上,它会   产生相同的结果[...]所以我   不能接受3个答案中的任何一个   那说查询是不同的

我并不是说他们生成相同的结果。为了更好地说明我的观点,让我提供一个类比。

假设我给你一堆洗牌的索引卡,编号从1到50,我说,“把这些都按顺序排列。”所以,你经历并整理它们,确保堆积从1到50.这需要你一两分钟。 然后我说,“现在把卡片放在最顶端。”这张卡恰好是编号为50的卡片。

另一方面,首先假设我所说的是“给我一张这个堆中编号最高的卡片。”然后,您要做的就是通过卡片找到编号最高的卡片,而无需进行任何排序。 (我的意思是,你可以先排序堆,但这显然比我要求的要多。)

所以我所说的是上述两组指令的结果是相同的;但是,它们显然是不同的说明

现在,如果某些实现足够智能,可以将这些实现转换为相同的(优化的)SQL查询,那么我一点都不会感到惊讶。我只是说,因为他们不同的指令,如果产生的SQL不同(并且它可能不幸,那么它应该不会那么令人惊讶) ,因此,当另一个版本没有时,一个版本可能会导致错误也就不足为奇了。


更新:同样,我无法就Linq-to-SQL提供详细的回复;但我要指出,虽然Max理论上应该与OrderByDescending一起产生FirstOrDefault相同的结果,但从概念的角度来看,它并不是真的相同

考虑Linq到对象。调用Max将遍历序列并累积最大值。调用OrderByDescending对整个序列进行排序,然后然后将其排在最前面。

显然,Linq-to-SQL是另一种动物;然而,有意义的是,由于这些查询代表了从概念上获得某种结果的不同方法,因此它们产生的SQL很可能(并且,正如您所见, )不同。


原始答案

我无法真正给出Linq-to-SQL的详细回复,但我会指出您的两种选择之间存在非常严重的差异(它们等效):

Max(x => x.Timestamp)

上面应该返回最大的时间戳

OrderByDescending(x => x.Timestamp()).FirstOrDefault()

以上内容应返回时间戳最大的记录

这些是非常不同的野兽。