2010-11-12 3 views
1

Следующий TSQL представляет собой пример того, как я могу решить эту проблему с SQL. Цель состоит в том, чтобы вернуть 1 строку на OID из левой таблицы, где количество записей в левой таблице равно количеству совпадающих строк в правой таблице.LINQ Left Join with Grouping and Convert this TSQL

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
  • Ваше 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} 

Цель состоит в том, чтобы вернуть 1 строку на OID из левой таблицы, где граф записей в левая таблица равна количеству совпадающих строк в правой таблице.

Исходя из этого описания, я бы написать:

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} 
+0

Приятное использование Lookups. Я всегда пропускаю этот метод. – Sorax

+0

Я дам ему попытку и обратную связь. Этот образец был упрощенной версией более сложного запроса, но имел особые проблемы. Примечание. Cs.OID уникален в Cars, поэтому нет необходимости в отличном использовании. Идея состоит в том, что у меня 3 строки в левой таблице, и я хочу вернуть строку только в том случае, если у меня также есть соответствующие 3 строки в правой таблице. Таким образом, Count (CS.OID) и SUM (rs.check) - в SQL, rs.check будет иметь значение null для не совпадений, а SQL игнорирует нули в сумме. – MikeH

+0

Если вы присоединяетесь ... cs.OID не будет уникальным в результате. И поскольку вы игнорируете нули, вам не нужно LEFT JOIN, чтобы игнорировать NULL. –

0

Я не уверен, я полностью понимаю, что желаемые результаты, но вот мой выстрел на него. Поле check не обязательно необходимо для LINQ, поскольку оно не служит никакой цели, кроме как для подсчета.

Я неправильно понял важность соединения и что сделало предложение 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 
       }; 
+0

Спасибо за попытку. В вашем примере я получаю две строки. Каждый из них содержит. OID = 1, CarCount = 1, RoadCount = 1. С данными в приведенном выше примере результаты должны быть пустыми, так как есть 3 машины и 2 дороги. Но если мы не полагаемся на HAVING, если мы просто вернем левое соединение, это будет одна строка с OID = 1, CarCount = 3, Roadcount = 2. Если бы я мог достичь этого, это был бы положительный ход вперед. – MikeH

+0

@Mike: Правильно, это дало бы две строки, так как мы присоединились, сопоставляя как «OID», так и «RID». Поскольку результат включает только «OID», они выглядят одинаково, поскольку мы оставили «RID». Но это было основано на моей интерпретации вашего TSQL-кода. Теперь, когда у меня есть лучшее представление о желаемых результатах, кажется, что мы должны группировать и присоединяться только к 'OID'. –

+0

Мы не можем просто группировать OID. Нам нужно сгруппировать по RID и OID, так как это то, что делает матч. Уловка заключается в том, что нам нужно найти группу RID + OID, где есть совпадения для всех строк в автомобилях. Например. Если я собираю сборку. Узел будет иметь 3 компонента. Чтобы знать, правильно ли построена сборка, мы должны сравнить сборку с правилами. Один из способов сделать это, и SQL показывает это) заключается в том, чтобы левый соединил сборку с правилами. Если правила состоят из трех компонентов, но сборка была составлена ​​только из двух компонентов, это неудачная сборка. (в этом случае нулевой результат) – MikeH