Макс (x => x.Time) vs OrderByDescending (x => x.Time) .First (). Время - PullRequest
2 голосов
/ 09 марта 2011

Я поднял связанный вопрос о:
'Неверное имя столбца [ColumnName]' для вложенного запроса linq

Я пытаюсь получить верхний ряд группы, как здесь:
Linq - максимальное значение из каждой группы

Однако я подошел к нему иначе, чем к принятому ответу, используя Макс. Я сделал это так:

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

Это приводит к ошибке SqlException: Invalid column name 'ID'

Теперь, когда я использую функцию Макс:

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

1 Ответ

4 голосов
/ 09 марта 2011

Обновление 2 : Я просто хочу ответить на это:

однако, если вы делаете что-то подобное на столе северного ветра, это будет производить тот же результат [...] Так что я не может принять ни одного из 3 ответов которые говорят, что запросы разные

Я не хотел спорить, что они должны дать тот же результат . Чтобы лучше проиллюстрировать мою точку зрения, позвольте мне привести аналогию.

Допустим, я даю вам перетасованную стопку учетных карточек, пронумерованных от 1 до 50, и говорю: «Приведите все это в порядок». Таким образом, вы проходите и сортируете их, убеждаясь, что куча идет от 1 до 50. Это займет у вас минуту или две. Тогда Я говорю: «Теперь дай мне карточку наверху колоды». Эта карта будет иметь номер 50.

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

Итак, я говорю, что результаты из двух вышеуказанных наборов инструкций будут одинаковыми; однако, они явно разные инструкции .

Теперь меня совсем не удивит, если некоторые реализации будут достаточно умными, чтобы перевести их в идентичные (оптимизированные) запросы SQL; все, что я говорю, это то, что, поскольку они являются различными инструкциями , не должно быть таким удивительным, если результирующий SQL отличается (и хотя это может быть неудачным поэтому неудивительно, что одна версия может вызвать ошибку, а другая - нет.


Обновление : Опять же, я не могу дать вам подробный ответ с точки зрения Linq-to-SQL; но я укажу, что хотя Max теоретически должно давать тот же результат , что и OrderByDescending вместе с FirstOrDefault, с концептуальной точки зрения это не совсем то же самое.

Рассмотрим Linq-to-objects. Вызов Max будет повторять последовательность и накапливать максимальное значение. Вызов OrderByDescending отсортирует всю последовательность и , затем возьмет верх.

Очевидно, что Linq-to-SQL - другое животное; однако имеет смысл, что, поскольку эти запросы представляют концептуально разные подходы для получения определенного результата, SQL-запрос, который они производят, вполне может быть (и, как вы видели, - это ) иным.


Оригинальный ответ

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

Max(x => x.Timestamp)

Выше должно возвращаться наибольшая отметка времени .

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

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

Это очень разные звери.

...