LINQ Group and Distinct

时间:2015-09-21 13:07:08

标签: linq

我仍然在理解LINQ。下面是我想要转换的SQL。我想要那些Max Seq等于同类的独特身份。

SELECT es.Ident
FROM   EqpSeq es
INNER JOIN EqpSeq esMax on esMax.Ident= es.Ident
WHERE    es.Class = 4
GROUP BY es.Ident, es.Seq
HAVING   es.Seq= Max(esMax.Seq);

数据看起来像

Ident     Seq     Class
10        1       4
10        2       5
10        3       4

Class = 4时的结果应为

Ident
10

Class = 5时的结果应为null。

我认为这个LINQ查询可能有效,但它返回两行Ident 10。

from es in EqpSeqs
join esMax in EqpSeqs on es.Ident equals esMax.Ident
where es.Class == 4
group es by new {
   es.Ident, es.Seq
} into g
where g.Key.Seq == g.Max(p => p.Seq)
select new {
   Ident = (int?)g.Key.Ident
}

任何想法都将不胜感激。我很想看到LINQ流畅的风格。

2 个答案:

答案 0 :(得分:0)

是的,根据您的样本数据,两次获得相同的值并不奇怪。您正在Ident上将表格连接到自身,但Ident的值在每一行中都相同。连接的结果基本上是行的笛卡尔积:

es.Ident  es.Seq  es.Class  esMax.Ident  esMax.Seq  esMax.Class
10        1       4         10           1          4
10        1       4         10           2          5
10        1       4         10           3          4
10        2       5         10           1          4
10        2       5         10           2          5
10        2       5         10           3          4
10        3       4         10           1          4  // This row matches
10        3       4         10           2          5
10        3       4         10           3          4  // So does this row

正如所建议的,在查询中添加Distinct应解决此问题:

(from es in EqpSeqs
join esMax in EqpSeqs on es.Ident equals esMax.Ident
where es.Class == 4
group es by new {
   es.Ident, es.Seq
} into g
where g.Key.Seq == g.Max(p => p.Seq)
select new {
   Ident = (int?)g.Key.Ident
})
.Distinct();

您也可以尝试几种不同的查询。

我经常使用Ix-Main NuGet包。该软件包附带了非常方便的MaxBy功能。如果你不介意添加该软件包,你可以这样做:

EqpSeq 
.GroupBy(x => new { x.Ident, x.Seq })
.MaxBy(x => x.Key.Seq)
.SelectMany(x => x)
.Where(x => x.Class == 4)
.Select(x => x.Ident)
.Distinct();

你可以在没有Ix-Main的情况下做同样的事情:

EqpSeq 
.Where(x => x.Seq == EqpSeq.Max(y => y.Seq) && x.Class == 4)
.Select(x => x.Ident)
.Distinct();

在我的头脑中,我不确定三个查询中哪一个最高效。如果Seq列被编入索引,那么我的赌注是第三个查询可能是赢家。

答案 1 :(得分:0)

谢谢大家的回复。我今天早上坐下来上班前大声说出我想要的东西,想出了以下内容,不确定这是否最有效:

SELECT es.EqpIdentID
FROM   EqpSeq es
WHERE  es.EqpClassID = 4 and 
       es.Seq = (SELECT Max(Seq) FROM EqpSeq esMax WHERE esMax.EqpIdentID = es.EqpIdentID)

Linqer制作的相应LINQ是:

from es in db.EqpSeqs
where
  es.EqpClassID == 4 &&
  es.Seq == 
  (from esMax in db.EqpSeqs
  where
  esMax.EqpIdentID == es.EqpIdentID
  select new {
  esMax.Seq
  }).Max(p => p.Seq)
select new {
es.EqpIdentID
}

LINQ Fluent / Method语法为:

EqpSeqs
  .Where(es => es.EqpClassID == 4 &&
               es.Seq == EqpSeqs
                 .Where(esMax => esMax.EqpIdentID == es.EqpIdentID).Max(a => a.Seq))
  .Select(b => b.EqpIdentID)