Left Join LINQ and using Bitwise Comparisons

橙三吉。 提交于 2019-12-10 19:27:06

问题


Left Join LINQ and using Bitwise Comparisons.

I have a problem that can be described as (thanks to David B for clarifying this): The goal is to return 1 row per OID from the Left Table, where the Count of the records in the left table is equal to the Count of the matching rows in the right table. A record matches when the OID, RID, and the FLAG is set in FLAGS for a row.

The Objects we are comparing have the following structure:

public class Roads : List<Road>{}
public class Road
{
    public int RID;
    public int OID;
    public int Check = 1;
    public long Flag;
}
public class Cars : List<Car> { }
public class Car
{
    public int RID;
    public int OID;
    public long Flags;
}

The objects a filled with the following data.

        Roads rs = new Roads();
        Cars cs = new Cars();

        Car c = new Car();
        c.OID = 1;
        c.RID = 1;
        c.Flags = 31; // 11111
        cs.Add(c);
        c = new Car();
        c.OID = 1;
        c.RID = 2;
        c.Flags = 31; //11111
        cs.Add(c);
        c = new Car();
        c.OID = 1;
        c.RID = 3;
        c.Flags = 4; //00100
        cs.Add(c);

        Road r = new Road();
        r.OID = 1;
        r.RID = 1;
        r.Flag = 8; //00010
        rs.Add(r);
        r = new Road();
        r.OID = 1;
        r.RID = 2;
        r.Flag = 2; //01000
        rs.Add(r);
        r = new Road();
        r.OID = 1;
        r.RID = 3;
        r.Flag = 4;  //01000
        rs.Add(r);
      //  r = new Road();
      //  r.OID = 1;
      //  r.RID = 3;
      //  r.Flag = 16;  //00001
      //  rs.Add(r);

To see if a flag is set you do a bitwise comparison, i.e. cs[0].Flags && rs[0].Flag > 0 is TRUE, cs[0].Flags & rs[0].Flag = 0 is FALSE

I have this general query that will get me the rows where the count of OID in cs = the count of matching OID in rs. I need a modified query now where the rest of the rules are applied. Where we check if the Flag is in the Flag for the specific row match.

    var carLookup = cs.ToLookup(cb => c.OID);
    var roadLookup = rs.ToLookup(rb => r.OID);

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

How can I extend this to get the additional filter conditions applied? What I am struggling with is having columns available where I need them to build the proper filter conditions. For example, I need to compare Flags && Flag. But how do I get so I have access to Flag and Flags to do the additional filter?

To Expand. I work mostly with TSQL, so I'm trying to mimic a logic flow I can easily apply in TSQL. If I was doing this with TSQL, it would look like this (note special case for 0):

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  
 AND (CS.FLAGS & RS.FLAG > 0
      OR (CS.FLAGS=0 AND RS.FLAG=0))
GROUP BY cs.OID  
HAVING Count(cs.OID) = Sum(RS.Check)   

With that statement, and the data above, the result would be 1, 3, 3.

If I were to comment the last add to Roads, and uncomment the next line, changing the Flag to 16, then the result would be: NULL Please comment if you need more info.


回答1:


I think this should be equivalent to your SQL statement, however it didn't produce the result you mentioned since your SQL uses RS.Check but you didn't assign any Check values in your sample code (you used r.OID). I went ahead and added r.Check = 1; to each Road object and was able to get the result you mentioned.

var query = from car in cs
            from road in rs
            where car.OID == road.OID
                && car.RID == road.RID
                && ((car.Flags & road.Flag) > 0 || (car.Flags == 0 && road.Flag == 0))
            group new { car, road } by car.OID into grouping
            let CarCount = grouping.Count()
            let RoadCount = grouping.Sum(o => o.road.Check)
            where CarCount == RoadCount
            select new { OID = grouping.Key, CarCount, RoadCount };


来源:https://stackoverflow.com/questions/4179550/left-join-linq-and-using-bitwise-comparisons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!