Как использовать подзапрос, groupby, max и top в одном операторе linqToSql? - PullRequest
3 голосов
/ 02 февраля 2009

Используя LinqToSql, мне нужно вернуть один (L) для самой последней даты modDate в соединительной таблице (CL).

Таблица:
L (крышка, meta1, meta2, ...)
CL (Cid, крышка, ModDate)

Вот sql, который дает ожидаемый результат

SELECT l.*
FROM L l
INNER JOIN (
    SELECT TOP 1 cl.Lid, MAX(cl.ModDate) as ModDate
    FROM CL cl
    INNER JOIN L l ON cl.Lid = l.Lid AND l.meta1 = 5
    GROUP BY cl.Lid
    ORDER BY MAX(cl.ModDate) DESC
) As m ON l.Lid = m.Lid

Ответы [ 3 ]

2 голосов
/ 02 февраля 2009

Достаточно просто. Подзапрос проецирует нас на идентификаторы. Запрос извлекает эти записи с соответствующими идентификаторами.

var subquery = db.L
    .Where(L => L.meta1 = 5)
    .SelectMany(L => L.CLs)
    .GroupBy(CL => CL.Lid)
    .OrderByDescending(g => g.Max(CL => CL.ModDate))
    .Select(g => g.Key)
    .Take(1)

var query = db.L
  .Where(L => subquery.Any(id => L.Lid == id))

Размышляя об этом дальше, вы можете уйти от подзапроса:

var query = db.L
  .Where(L => L.meta1 = 5)
  .SelectMany(L => L.CLs)
  .GroupBy(CL => CL.Lid)
  .OrderByDescending(g => g.Max(CL => CL.ModDate))
  .Select(g => g.First().L);
1 голос
/ 02 февраля 2009

По вашему запросу я могу интерпретировать этот Linq.

var query = from l in Context.L
            join m in (from cl in Context.CL
                       join l in Context.L on cl.Lid equals l.Lid 
                       where l.meta1 == 5
                       group new { l.Lid, cl.ModDate } by cl.Lid into grp
                       select new { Lid = grp.Key, ModDate = grp.Max(g => g.ModDate) }  into grp
                       order by grp.ModDate descending
                       select grp).Take(1) on l.Lid equals m.Lid
            select l;
1 голос
/ 02 февраля 2009

Мой SQL-фу не сказочный, и это до моего первого кофе, так что я предполагаю, что «l» во внешнем запросе в конечном итоге будет совершенно другим «l» по сравнению с тем, что в подзапросе?

Я думаю, это сработает, но вам нужно быть уверенным :) Стоит проверить, как выглядит сгенерированный SQL. Конечно, если вы не возражаете против выполнения двух запросов, это будет несколько проще.

// Can't do the "Take(1)" here or it will be executed separately
var subquery = from cl in context.CL
               join l in context.L on cl.Lid = l.Lid
               where l.meta1 = 5 // could put this in join clause
               group cl.ModDate by cl.lid into grouped
               order by grouped.Max() descending
               select grouped.Key;

// But can take the first result of the join
// This may be simpler using dot notation instead of a query expression
var query = (from l in context.L
            join lid in subquery
            select l).Take(1);

(РЕДАКТИРОВАТЬ: я не принимал максимальное значение ModDate раньше. Doh. Также упростил группировку, используя идентификатор в качестве ключа (который уже был), поэтому нам нужны только ModDate в качестве значений группы.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...