简体   繁体   English

怎么把Group By SQL转换成LINQ?

[英]How to convert Group By SQL to LINQ?

I have the following SQL statement I'm trying to convert to Entity Framework. 我尝试将以下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)

I've done some searching on using Group By in LINQ as well as sub-queries. 我已经在LINQ中使用Group By以及子查询进行了一些搜索。 I'm using LinqPad with a "C# Statement" and I came up with the following which based on some examples I found looks like it should work. 我使用带有“ C#语句”的LinqPad,并根据以下发现的示例得出了以下结论: However, I'm getting errors when trying to assign esn.S_NUMBER to sNumber in the anonymous object. 但是,尝试将esn.S_NUMBER分配给匿名对象中的sNumber时出现错误。 The message says 'IGrouping' does not contain a definition for 'S_NUMBER'. 消息显示“ 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();

I was under the impression that all the records would basically get put into a temp table called esn and I could be able to call the temptable.column name to assign it to my object that I will eventually return as a list. 我的印象是,所有记录基本上都将放入一个名为esn的临时表中,我可以调用temptable.column名称将其分配给我的对象,最终我将以列表形式返回该对象。

You want to use Key instead of S_NUMBER . 您想使用Key而不是S_NUMBER When grouping, the results get put into a IEnumerable<IGrouping>> . 分组时,结果放入IEnumerable<IGrouping>> The grouping has a Key property which holds the key for that group, which in this case it's your S_NUMBER . 分组具有Key属性,该属性保存该组的密钥,在本例中为您的S_NUMBER

select new
{
    sNumber = esn.Key
};

The following query should be a translation of the original SQL query. 以下查询为原始SQL查询的翻译。 Instead of using a subquery, we're grouping and doing another from...in to "flatten" the sequence, and also checking that each grouping has a count > 1 like the original query. 而不是使用子查询,我们将分组并from...in进行另一个操作以“拉平”序列,并检查每个分组是否像原始查询一样具有count > 1count > 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
             };

Since you're using the results of one query to filter another we can do a fairly direct transliteration of the query like so: 由于您使用的是一个查询的结果来过滤另一个查询的结果,因此我们可以对查询进行相当直接的音译,如下所示:

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 };

Not only does this look a lot more like the original query but it should perform a bit faster (on MS SQL at least, can't speak for others) than the other form that might be simpler in LINQ but is much more complex when converted to SQL... four selects and a cross join, in my test version, vs two selects and an inner join for this one. 这不仅看起来更像原始查询,而且它的执行速度(至少在MS SQL上,不能代表其他人)要比LINQ中可能更简单但转换时要复杂得多的其他形式要快一些。到SQL ...在我的测试版本中,有四个选择和一个交叉联接,而与此相比,两个选择和一个内部联接。

Of course if you prefer you can pull the inner query out as a separate IQueryable for clarity: 当然,如果您愿意,可以将内部查询作为单独的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 };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM