如何将 Group By SQL 转换为 LINQ?

How to convert Group By SQL to LINQ?

我正在尝试将以下 SQL 语句转换为 Entity Framework。

SELECT S_NUMBER,A_NUMBER,FIRST_NAME,LAST_NAME
FROM EMPLOYEE WHERE S_NUMBER IN (
        SELECT S_NUMBER
        FROM EMPLOYEE 
        WHERE CO='ABC'
        GROUP BY S_NUMBER
        HAVING COUNT(*) > 1)

我已经对在 LINQ 中使用分组依据以及子查询进行了一些搜索。我将 LinqPad 与 "C# Statement" 一起使用,并根据我发现的一些示例提出了以下内容,它看起来应该可以工作。但是,在尝试将 esn.S_NUMBER 分配给匿名对象中的 sNumber 时出现错误。消息说 'IGrouping' 不包含 'S_NUMBER' 的定义。

 var result = from e in EMPLOYEE    
              where e.CO=="ABC" 
              group e by e.S_NUMBER into esn      
              select new
              {
                  sNumber = esn.S_NUMBER
              };


result.Dump();

我的印象是所有记录基本上都会被放入一个名为 esn 的临时 table 中,我可以调用 temptable.column 名称将其分配给我的对象最终将 return 作为列表。

您想使用 Key 而不是 S_NUMBER。分组时,结果会放入 IEnumerable<IGrouping>> 中。该分组有一个 Key 属性 保存该组的密钥,在本例中它是您的 S_NUMBER.

select new
{
    sNumber = esn.Key
};

以下查询 应该 是原始 SQL 查询的翻译。我们不使用子查询,而是分组并执行 another from...in 到 "flatten" 序列,并检查每个分组是否有一个 count > 1就像原始查询一样。

var result = from e in EMPLOYEE
             where e.CO=="ABC"
             group e by e.S_NUMBER into esn
             from e2 in esn
             where esn.Count() > 1
             select new
             {
                 e.S_NUMBER,
                 e.A_NUMBER,
                 e.FIRST_NAME,
                 e.LAST_NAME
             };

由于您使用一个查询的结果来过滤另一个查询,我们可以像这样对查询进行相当直接的音译:

var result =
    from e in EMPLOYEE
    join f in (
        from fe in EMPLOYEE
        where fe.CO == 'ABC'
        group null by S_NUMBER into grp
        where grp.Count() > 1
        select grp.Key
    )
    on e.S_NUMBER equals f
    select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };

这不仅看起来更像原始查询,而且它的执行速度应该比其他可能更简单的形式快一点(至少在 MS SQL 上,不能代表其他人)在 LINQ 中,但在转换为 SQL 时要复杂得多...四个选择和一个交叉连接,在我的测试版本中,与两个选择和一个内部连接相比。

当然,如果您愿意,为了清楚起见,您可以将内部查询作为单独的 IQueryable 拉出:

var filter = 
    from e in EMPLOYEE
    where e.CO == 'ABC'
    group null by S_NUMBER into grp
    where grp.Count() > 1
    select grp.Key;

var result =
    from e in EMPLOYEE
    join f in filter
    on e.S_NUMBER equals f
    select new { e.S_NUMBER, e.A_NUMBER, e.FIRST_NAME, e.LAST_NAME };