2

我提出了一个相关问题:
嵌套 linq 查询中的“列名无效 [ColumnName]”

我正在尝试按照此处的要求获取组的第一行:
Linq - 每个组的最高值

但是,我使用 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
一些答案说这些查询在逻辑上是不同的,但是,如果你在北风表上做这样的事情,它会产生相同的结果:

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 转换为列表。

4

1 回答 1

4

更新 2:我只想对此作出回应:

但是,如果您在 Northwind 表上执行此类操作,它将产生相同的结果 [...] 所以我不能接受 3 个回答中的任何一个说查询不同

我并不是要争论他们应该产生同样的结果。为了更好地说明我的观点,让我提供一个类比。

假设我给你一堆打乱的索引卡,编号从 1 到 50,然后我说:“把这些都按顺序排列。” 所以,你把它们整理出来,确保堆从 1 到 50。这需要你一两分钟。然后我说,“现在把牌堆顶上的牌给我。” 这张卡恰好是编号为 50 的卡。

另一方面,假设我首先说的是,“给我这张牌中数字最高的牌。” 然后,您要做的就是浏览卡片并找到数字最高的卡片,而无需进行任何排序。(我的意思是,你可以先对这堆东西进行分类,但这显然比我要求的要多。)

所以我说的是上面两组指令的结果是一样的但是,它们显然是不同的指令

现在,如果某些实现足够智能,可以将它们转换为相同的(优化的)SQL 查询,我一点也不感到惊讶。我要说的是,由于它们不同的指令,因此如果生成的 SQL 不同(尽管可能很不幸,但一个版本在另一个版本可能导致错误)也不足为奇没有)。


更新:再说一次,我真的不能就 Linq-to-SQL 给你一个详细的答复;但我要指出,虽然Max理论上应该与 一起产生相同的结果,但从概念的角度来看并不完全相同。OrderByDescendingFirstOrDefault

考虑 Linq 到对象。调用Max将遍历序列并累积最大值。调用OrderByDescending将对整个序列进行排序然后占据顶部。

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


原始答案

关于 Linq-to-SQL,我真的不能给你一个详细的答复,但我会指出,你的两个替代方案之间存在非常严重的差异(它们等价):

Max(x => x.Timestamp)

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

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

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

这些是非常不同的野兽。

于 2011-03-09T02:10:50.940 回答