LINQ左连接分组并转换此TSQL

时间:2010-11-12 19:54:55

标签: linq linq-to-objects

以下TSQL提供了一个如何使用SQL解决此问题的示例。目标是从左表中返回每个OID 1行,其中左表中的记录计数等于右表中匹配行的计数。

SELECT cs.OID, Count(cs.OID) AS CarCount, Sum(RS.Check) AS RoadCount  
   FROM Cars AS cs  
LEFT JOIN Roads AS RS  
  ON CS.oid = RS.OID  
   AND cs.RID = RS.RID  
  GROUP BY cs.OID  
  HAVING Count(cs.OID) = Sum(RS.Check)  

使用下面的对象设置,是否有可以构造的等效LINQ查询,或者这是不可能的?请注意为Road类的声明中检查的默认值。在下面的设置示例中,结果应为零匹配。添加一个具有适当值的道路将使其返回一个。至少那是理想的。

我遇到的问题是,这种类型的TSQL代码对于LINQ来说太复杂了。我没有找到一个明显的或非显而易见的解决方案来实现类似的行为。因此,我相信也许解决方案是停止尝试复制SQL并做一些不同的事情。由于LINQ经验不足,我不知道从哪里开始。

public class Roads : List<Road>{}  
public class Road  
{  
    public int RID;  
    public int OID;  
    public int check = 1;  
}  
public class Cars : List<Car> { }  
public class Car  
{  
    public int RID;  
    public int OID;  
}  

private void CheckCheck()  
{  
    Roads rs = new Roads();  
    Cars cs = new Cars();  

    Car c = new Car();  
    c.OID = 1;  
    c.RID = 1;  
    cs.Add(c);  
    c = new Car();  
    c.OID = 1;  
    c.RID = 2;  
    cs.Add(c);  
    c = new Car();  
    c.OID = 1;  
    c.RID = 3;  
    cs.Add(c);  

    Road r = new Road();  
    r.OID = 1;  
    r.RID = 1;  
    rs.Add(r);  
    r = new Road();  
    r.OID = 1;  
    r.RID = 2;  
    rs.Add(r);  

    // Results should be :  
    // OID where Count of OID from C = Count of OID from R  
}  

2 个答案:

答案 0 :(得分:2)

  • 您的HAVING条款会过滤掉任何与道路不匹配的车辆。这使得左连接成为内连接。
  • 你有COUNT(cs.OID)说它正在计算汽车,但事实并非如此。你的意思可能是COUNT(DISTINCT cs.OID)

这是一个字面翻译:

from c in Cars
join r in Roads on new {c.OID, c.RID} equals new {r.OID, r.RID}
group new {Car = c, Road = r} by c.OID into g
let carCount = g.Count()  //did you mean g.Select(x => x.Car.OID).Distinct().Count()
let roadCount = g.Sum(x => x.Road.Check)
where carCount = roadCount
select new {OID = g.Key, CarCount = carCount, RoadCount = roadCount}

  

目标是从左表中每个OID返回1行,其中左表中的记录计数等于右表中匹配行的计数。

根据这个描述,我写道:

var carLookup = Cars.ToLookup(c => c.OID);
var roadLookup = Roads.ToLookup(r => r.OID);

from x in carLookup
let carCount = x.Count()
let roadCount = roadLookup[x.Key].Count()
where carCount = roadCount
select new {OID = g.Key, CarCount = carCount, RoadCount = roadCount}

答案 1 :(得分:0)

我不确定我是否完全理解所期望的结果是什么,但这是我拍摄的结果。 LINQ并不一定需要check字段,因为除了计数之外它不起任何作用。

我误解了连接的重要性以及HAVING子句对查询的作用。它现在回到原来的TSQL版本,但改变了RoadCount计算。我相信这就是你要求的。

var results = from Car in cs
              join road in rs
                  on new { Car.OID, Car.RID } equals new { road.OID, road.RID }
                  into Roads
              group roads by Car.OID into cars
              let CarCount = cars.Count()
              let RoadCount = cars.Sum(roads => roads.Count())
              where CarCount == RoadCount
              select new
              {
                  OID = cars.Key,
                  CarCount,
                  RoadCount
              };