2012-02-28 2 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을 생성하지 못합니다. Group By 및 Having을 사용하는 대신 Customer 쿼리의 각 행에서 Count에 대해 하위 쿼리를 수행합니다. LINQ Group By 구문 작업을 시도했지만 HAVING 절이 아닌 WHERE 절을 그대로 사용했습니다.

아이디어가 있으십니까? 아래 답변에 응답

편집 :

가 언급 한 문제를 해결로 나는 내가 원래 가지고 질의를함으로써 그룹을 생성하지 않는 경우에도, JamieSee의 답변을 수용하고있다.

감사의 말씀을 전합니다. 내가 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 

내가 가진 문제는 내가해야한다는 것입니다을 "jl"을 "Key"그룹에 푸시합니다. 그래서 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 부분 대신에 특정 숫자를 물어 본 경우,이 대답은 NOT EXISTS가 COUNT = 0을 의미하는 것으로 더 이상 작동하지 않는다고 생각합니다. LINQ-to-Entities가 SQL GROUP BY를 생성하도록 설득 할 수있는 더 넓은 질문은 여전히 ​​남아 있습니다. 예제와 같은 구문이 있습니다. –

+0

someting을 사용한 답변이 업데이트되었습니다. 원본 SQL을 생성해야한다고 생각합니다. 나는 업데이트 된 부분을 테스트하지 않았다. 이것이 당신에게 어떤 역할을하는지 알려주세요. – JamieSee

0

하드 그냥 tipp의 bocuse 생성 modells없이 쿼리를 작성하는 (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 
      };