如何在单个linq To Sql语句中使用子查询,分组依据,最大值和最高值?

时间:2009-02-02 07:08:32

标签: linq linq-to-sql

使用LinqToSql,我需要为连接表(CL)中的最新modDate返回单个(L)。

表:
L(Lid,meta1,meta2,...)
CL(Cid,Lid,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 个答案:

答案 0 :(得分:2)

足够简单。子查询向我们展示了ID。查询将使用匹配的ID获取这些记录。

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 :(得分:1)

我的SQL-fu并不神奇,而且是在我的第一杯咖啡之前,所以我假设外部查询中的“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。还使用ID作为键(它已经是)来简化分组,因此我们只需要将ModDate作为组值。)

答案 2 :(得分:1)

作为您提供的查询,我可以解释为此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;