Left Join LINQ и использование побитовых сравнений - PullRequest
3 голосов
/ 14 ноября 2010

Left Join LINQ и использование побитовых сравнений.

У меня есть проблема, которую можно описать как (спасибо David B за разъяснение этого): цель состоит в том, чтобы вернуть 1 строку на OID из левой таблицы,где Количество записей в левой таблице равно количеству совпадающих строк в правой таблице.Запись совпадает, когда OID, RID и FLAG установлены в FLAGS для строки.

Объекты, которые мы сравниваем, имеют следующую структуру:

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

Объекты, заполненныеследующие данные.

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

Чтобы увидеть, установлен ли флаг, вы выполняете побитовое сравнение, т.е. cs [0] .Flags && rs [0] .Flag> 0 - TRUE, cs [0].Flags & rs [0] .Flag = 0 равно FALSE

У меня есть общий запрос, в котором я получу строки, в которых количество OID в cs = количество совпадающих OID в rs.Мне нужен измененный запрос сейчас, где применяются остальные правила.Где мы проверяем, находится ли флаг во флаге для конкретного совпадения строк.

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

Как я могу расширить это, чтобы применить дополнительные условия фильтра?То, с чем я борюсь, - это наличие столбцов, где они мне нужны, чтобы создать правильные условия фильтрации.Например, мне нужно сравнить флаги и флаг.Но как мне получить доступ к Флагу и Флагу, чтобы выполнить дополнительный фильтр?

Расширить.Я работаю в основном с TSQL, поэтому я пытаюсь имитировать логический поток, который легко применить в TSQL.Если бы я делал это с TSQL, это выглядело бы так (обратите внимание на особый случай для 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)   

С этим оператором и данными выше результат будет 1, 3, 3.

Если бы я прокомментировал последнее добавление к дорогам и раскомментировал следующую строку, изменив флажок на 16, результат был бы: NULL Пожалуйста, прокомментируйте, если вам нужна дополнительная информация.

1 Ответ

0 голосов
/ 15 ноября 2010

Я думаю, что это должно быть эквивалентно вашему выражению SQL, однако оно не дало упомянутого вами результата, так как ваш SQL использует RS.Check, но вы не присвоили значения Check в своем примере кода (вы использовали r.OID). Я пошел дальше и добавил r.Check = 1; к каждому Road объекту и смог получить упомянутый вами результат.

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