2012-02-28 77 views
0

我有以下SQL查詢返回所有沒有訂單沒有任何零件分配的客戶 - 即我只想要其中命令行的訂單每個訂單沒有分配的部分 - (在我處理的不同域,但已轉化爲客戶/訂單來說明問題的實際問題)集團通過具有和計數爲LINQ查詢與多重嵌套表

SELECT c.Customer_PK 
FROM Customers c 
    INNER JOIN Orders o 
    ON c.Customer_PK = o.Customer_FK 
    LEFT OUTER JOIN OrderLines l 
    ON o.Order_PK = l.Order_FK 
    LEFT OUTER JOIN Parts p 
    ON l.OrderLine_PK = p.OrderLine_FK 
GROUP BY c.Customer_PK 
HAVING COUNT(p.Part_PK) = 0 

我在LINQ拿出最好如下:

Dim qry =  
(From c In context.Customers 
Select New With { c.Customer_PK, 
        .CountParts = 
         (From o In c.Orders 
      From l In o.OrderLines 
         Select l.Parts.Count).DefaultIfEmpty.Sum}) 

qry = (From grp In qry 
     Where grp.CountParts = 0 
     Select grp.Customer_PK) 

這可以工作,但會生成少於最優的SQL - 它爲客戶查詢的每一行上的Count進行子查詢,而不是使用Group By和Having。我試着讓LINQ Group By語法工作,但它一直把過濾器作爲WHERE而不是HAVING子句。

任何想法?

編輯迴應如下回答:

我接受JamieSee的回答,因爲它解決了上述問題,即使它不會產生GROUP BY HAVING查詢我本來。

感謝Peter和Nick對此提出的意見。我是一個VB開發人員,所以我有一個裂縫翻譯你的代碼VB,這是我得到的最接近的,但它並不完全產生所需的輸出:

Dim qry = From c In context.Customers 
      Group Join o In context.Orders On c.Customer_PK Equals o.Customer_FK 
      Into joinedOrders = Group 
      From jo In joinedOrders.DefaultIfEmpty 
      Group Join l In context.OrderLines On jo.Order_PK Equals l.Order_FK 
      Into joinedLines = Group 
      From jl In joinedLines.DefaultIfEmpty 
      Group c By Key = New With {c.Customer_PK, jl} Into grp = Group 
      Where Key.jl Is Nothing OrElse Not Key.jl.Parts.Any 
      Select c.Customer_PK 

我的問題是,我有通過「Key」將「jl」推入組中,這樣我就可以從Where子句中引用它,否則編譯器無法看到該變量或出現在Group By子句之前的任何其他變量。

使用指定的過濾器,我可以獲得所有客戶,其中至少有一個訂單有沒有零件的行,而不是隻有沒有任何訂單的零件的客戶。

回答

2

既然你不關心只計算最終的客戶,請考慮以下問題的重述:

確定所有沒有任何訂單且包含具有部件的訂單的客戶。

這產生了:

var customersWithoutParts = from c in Context.Customers 
          where !(from o in Context.Orders 
            from l in o.Lines 
            from p in l.Parts 
            select o.Customer_FK).Contains(c.Customer_PK) 
          select c.Customer_PK; 

這應該產生髮出SQL這大致相當於以下內容:

SELECT  c.Customer_PK 
FROM   Customers AS c 
WHERE  (NOT EXISTS 
          (SELECT  o.Cusomer_FK 
          FROM   Orders AS o INNER JOIN 
                OrderLines AS l ON o.Order_PK = l.Order_FK INNER JOIN 
                Parts AS p ON l.OrderLine_PK = p.OrderLine_FK 
          WHERE  (o.Customer_FK = c.Customer_PK))) 

爲了讓你試圖重現SQL,我試圖啓動如下:

var customersWithoutParts = from c in Context.Customers 
          from o in c.Orders.DefaultIfEmpty() 
          from l in o.Lines.DefaultIfEmpty() 
          join part in Context.Parts on part.OrderLine_FK equals l.OrderLine_PK into joinedParts 
          where joinedParts.Count() == 0 
          select c.Customer_PK; 

請注意,在VB中join這裏將是代表由Group Join交易。

+0

感謝這個,我接受這個答案,因爲它適用於我給出的例子,並給出合理的SQL。如果不是NO部分我要求一個具體的數字,那麼這個答案我不會再工作,因爲不存在暗示COUNT = 0的問題。更廣泛的問題仍然是如何讓LINQ-to-Entities能夠生成SQL GROUP BY和HAVING語法就像例子。 – 2012-02-29 11:03:46

+0

更新的答案與某些我認爲應該產生您的原始SQL。我還沒有測試更新的部分。讓我知道這對你的影響。 – JamieSee 2012-02-29 17:07:22

0

只是TIPP博古斯努力創造沒有產生型號查詢(C#):

from o in dc.Orders 
join jOrderLines in dc.OrderLines on o.Order_PK equals jOrderLines.Order_FK into joinedOrderlines 
from l in joinedOrderLines.DefaultIfEmpty() 
group o by o.Customer_FK into g 
where l == null || l.Count(x => x.Parts) == 0 
select g.Key 
0

什麼是這樣的:

var qry = from c in db.Customers 
      join o in db.Orders.Where(x => x.Customer_FK == c.Customer_PK) 
      join l in db.OrderLines.Where(x => x.Order_FK = o.Order_PK).DefaultIfEmpty() 
      join p in db.Parts.Where(x => x.OrderLine_FK = l.OrderLine_PK).DefaultIfEmpty() 
      group c by new 
      { 
       c.Customer_PK 
      } into g 
      where g.Count(p => p.Part_PK != null) == 0 
      select new 
      { 
       Customer_PK = g.Key.Customer_PK 
      };