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();

したがって、クエリが異なる、Max がリストの最大値ではなく Sum を指定している、または先に進む前に IQueriable をリストに変換する必要があるという 3 つの回答のいずれも受け入れることができません。

4

1 に答える 1

4

更新 2 : 私はこれに応答したい:

ただし、ノースウィンド テーブルでこのようなことを行うと、同じ結果が生成されます [...] したがって、クエリが異なるという 3 つの回答のいずれも受け入れることができません。

私は、それらが同じ結果をもたらすべきであることに異議を唱えるつもりはありませんでした。私の要点をよりよく説明するために、例えを挙げましょう。

1 から 50 までの番号が付けられたインデックス カードのシャッフルされた山をあなたに渡し、「これらをすべて順番に並べてください」と言ったとしましょう。そのため、パイルが 1 から 50 になるように並べ替えます。これには 1 ~ 2 分かかります。それから私は言いました。このカードはたまたま50番のカードです。

一方、そもそも私が「この山から最も高い数字のカードをくれ」とだけ言ったとします。次に、カードを調べて、番号が最も高いカードを見つけるだけで、並べ替えを行う必要はありません。(つまり、最初に山を並べ替えることができますが、それは明らかに私が求めた以上のことをするでしょう。)

つまり、上記の 2 つの命令セットの結果は同じになるということです。ただし、これらは明らかに異なる命令です。

さて、特定の実装がこれらを同一の (最適化された) SQL クエリに変換するのに十分なほどインテリジェントであったとしても、まったく驚かないでしょう。私が言っているのは、それら異なる命令であるため、結果のSQLが異なっていてもそれほど驚くべきことではないということです(残念なことかもしれませんが、したがって、あるバージョンが別のバージョンでエラーを引き起こす可能性があることも驚くべきことではありませんしません)。


更新: 繰り返しますが、Linq-to-SQL に関して詳細な回答を提供することはできません。しかしMax、理論上は とを組み合わせた場合と同じ結果になるはずですが、概念的な観点からは実際には同じではないことを指摘しておきます。OrderByDescendingFirstOrDefault

Linq-to-objects を検討してください。呼び出しMaxはシーケンスを反復し、最大値を累積します。呼び出すと、シーケンス全体OrderByDescendingがソートされてから、一番上になります。

明らかに、Linq-to-SQL は別の動物です。ただし、これらのクエリは特定の結果を取得するための概念的に異なるアプローチを表しているため、生成される SQL が異なる可能性が非常に高い (そして、ご覧のとおり) ことは理にかなっています。


元の回答

Linq-to-SQL に関して詳細な回答を提供することはできませんが、2 つの選択肢には非常に重大な違いがあることを指摘します (それらは同等ではありません)。

Max(x => x.Timestamp)

上記は、最大の timestampを返す必要があります。

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

上記は、タイムスタンプが最大のレコードを返す必要があります。

これらは非常に異なる獣です。

于 2011-03-09T02:10:50.940 に答える