2010-11-12 80 views
1

以下TSQL提供的我會如何解決這個問題,SQL的例子。目標是從左表中返回每個OID 1行,其中左表中的記錄計數等於右表中匹配行的計數。LINQ左連接與分組並具有轉換這個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查詢,或者這是不可能的?注意道路類聲明中檢查的默認值。在下面的設置示例中,結果應該是零匹配。添加一個具有適當值的道路將使它返回一個。至少這是理想的。

我所遇到的問題是,它似乎這種類型的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} 

目標是左表,返回每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} 
+0

尼斯使用的查找。我總是忽視那種方法。 – Sorax 2010-11-12 20:25:46

+0

我會試一試並提供反饋。此示例是更復雜的查詢的簡化版本,但具有特定的問題點。注意cs.OID在汽車中是獨一無二的,所以不需要區分。這個想法是我在左表中有3行,並且我想只在右表中匹配3行時才返回一行。因此,對於非匹配,SQL(rs.check)中的Count(CS.OID)和SUM(rs.check)將爲空,並且SQL忽略總和中的空值。 – MikeH 2010-11-12 21:20:43

+0

如果您加入... cs.OID在結果中不會是唯一的。而且由於你忽略了空值,所以你不需要使用LEFT JOIN來爲你忽略空值。 – 2010-11-12 21:30:47

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

感謝您的嘗試。用你的例子,我結束了兩行。每個包含。 OID = 1,CarCount = 1,RoadCount = 1。根據上面示例中的數據,結果應該爲空,因爲有3輛車和2條道路。但是如果我們不依賴HAVING,如果我們只返回左連接,它將是一個OID = 1,CarCount = 3,Roadcount = 2的單行。如果我能做到這一點,這將是一個積極的舉措前鋒。 – MikeH 2010-11-13 21:52:29

+0

@Mike:對,它會產生兩行,因爲我們通過匹配'OID'和'RID'來加入。由於結果只包含'OID',因爲我們忽略了'RID',所以它們看起來完全相同。但這是基於我對您的TSQL代碼的解釋。現在我對想要的結果有了更好的瞭解,看起來我們應該將它們分組並加入到「OID」中。 – 2010-11-14 00:44:12

+0

我們不能只在OID上進行分組。我們需要對RID和OID進行分組,因爲這是匹配的。值得注意的是,我們需要找到RID + OID的分組,其中有與汽車中所有行匹配的分組。例如。如果我正在建造一個裝配。該組件將有3個組件。要知道構建的程序集是否正確,我們必須將構建與規則進行比較。一種方式來做到這一點,SQL顯示這一點)是左側將構建加入到規則中。如果規則由3個組件構成,但構建只由2個組件構成,則構建失敗。 (在這種情況下,結果爲空) – MikeH 2010-11-14 16:55:25