LINQ to SQL 왼쪽 외부 조인


140

이 쿼리는 LEFT OUTER조인 과 동일 합니까?

//assuming that I have a parameter named 'invoiceId' of type int
from c in SupportCases
let invoice = c.Invoices.FirstOrDefault(i=> i.Id == invoiceId)
where (invoiceId == 0 || invoice != null)    
select new 
{
      Id = c.Id
      , InvoiceId = invoice == null ? 0 : invoice.Id
}

답변:


167

왼쪽-외부 조인의 각 "왼쪽"행은 0-n "오른쪽"행 (두 번째 테이블)과 일치하므로 0-1 만 일치합니다. 왼쪽 외부 조인을 수행하려면, 당신은 필요 SelectMany하고 DefaultIfEmpty, 예를 들면 :

var query = from c in db.Customers
            join o in db.Orders
               on c.CustomerID equals o.CustomerID into sr
            from x in sr.DefaultIfEmpty()
            select new {
               CustomerID = c.CustomerID, ContactName = c.ContactName,
               OrderID = x == null ? -1 : x.OrderID };   

( 또는 확장 방법을 통해 )


19
누군가이 미친 구문이 어떻게 작동하는지 설명 할 수 있습니까? 나는 어떤 키워드가 마술처럼 왼쪽 조인이되는지 보지 못합니다. "into sr"은 무엇을합니까? Linq는 때때로 저를 좌절
Joe Phillips

2
@JoePhillips SQL 경험이 많지만 LINQ를 배우는 것은 진흙을 넘어가는 것과 같습니다. 나는 그것이 절대적으로 미친 것에 동의합니다.
Nick.McDermaid 2018 년

@ 마크 - gravell : 당신은 LINQ 변환 내 SQL 쿼리 해결에 나를 도울 수 stackoverflow.com/questions/28367941/...
이씨는 I 파틸

@VishalIPatil SQL에서 LINQ로 변환 하시겠습니까? SQL은 잘 작동하고 훨씬 더 예측 가능하고 효율적입니다 ...
Marc Gravell

1
@VishalIPatil 그래서 ... 왜 그럴까요? 거의 모든 LINQ 도구에는 직접 작성된 SQL을 실행할 수있는 기능이 포함되어 있습니다. 왜 그렇게하지 않습니까?
Marc Gravell

216

into 문은 필요하지 않습니다.

var query = 
    from customer in dc.Customers
    from order in dc.Orders
         .Where(o => customer.CustomerId == o.CustomerId)
         .DefaultIfEmpty()
    select new { Customer = customer, Order = order } 
    //Order will be null if the left join is null

그리고 예, 위의 쿼리는 실제로 LEFT OUTER 조인을 만듭니다.

여러 왼쪽 조인을 처리하는 비슷한 질문에 연결 : Linq to Sql : 여러 왼쪽 외부 조인


14
@Marc Gravvel의 답변이 효과가 있다는 것을 알고 있지만 IMO는 왼쪽 조인의 모양과 더 일치하기 때문에이 방법을 선호합니다.
llaughlin

1
훌륭한 답변입니다. 5 시간 이상의 Google 검색을 찾고 있습니다. 이것이 결과 SQL이 결합 할 수있는 유일한 방법입니다.
파이살 Mq

1
너무 감사합니다 .... 나는 오후 내내 이것에 대한 해결책을 찾고 있었고 당신의 코드는 그것을 못 박았습니다 (부팅하기 자연 스럽습니다). 이것을 여러 번 공표 할 수 있기를 바랍니다.
Jim

2
@ Jim thanks :-) 개발자 가이 답변에서 여전히 마일리지를 얻고있어 기쁩니다. DefaultIfEmpty ()가 into 문을 사용하는 것보다 훨씬 자연스럽게 느껴진다는 것에 완전히 동의합니다.
Amir

7
내가 방금 한 것처럼 이것을 찾는 다른 사람을위한 참고 사항입니다. 이로 인해 CROSS APPLY 내부에 LEFT OUTER JOIN이 생깁니다. 즉, 조인의 오른쪽에 여러 개의 일치 항목이 있으면 중복이 발생합니다. Marc Gravell의 솔루션은 "예쁜"것은 아니지만 내가 원했던 적절한 SQL 출력과 결과 세트를 주었다.
Mike U


5

1 솔루션을 찾았습니다. 이런 종류의 SQL (왼쪽 조인)을 Linq 엔터티로 변환하려면 ...

SQL :

SELECT * FROM [JOBBOOKING] AS [t0]
LEFT OUTER JOIN [REFTABLE] AS [t1] ON ([t0].[trxtype] = [t1].[code])
                                  AND ([t1]. [reftype] = "TRX")

LINQ :

from job in JOBBOOKINGs
join r in (from r1 in REFTABLEs where r1.Reftype=="TRX" select r1) 
          on job.Trxtype equals r.Code into join1
from j in join1.DefaultIfEmpty()
select new
{
   //cols...
}

Linq-to-SQL 엔티티는 지원하지 않는 이 주석을 참조하십시오 DefaultIfEmpty.
TJ Crowder

2

한 가지 더 추가하고 싶습니다. LINQ to SQL에서 DB가 올바르게 빌드되고 테이블이 외래 키 제약 조건을 통해 관련된 경우에는 조인을 전혀 수행 할 필요가 없습니다.

LINQPad를 사용하여 다음 LINQ 쿼리를 만들었습니다.

//Querying from both the CustomerInfo table and OrderInfo table
from cust in CustomerInfo
where cust.CustomerID == 123456
select new {cust, cust.OrderInfo}

아래의 (약간 잘린) 쿼리로 번역 된 것

 -- Region Parameters
 DECLARE @p0 Int = 123456
-- EndRegion
SELECT [t0].[CustomerID], [t0].[AlternateCustomerID],  [t1].[OrderID], [t1].[OnlineOrderID], (
    SELECT COUNT(*)
    FROM [OrderInfo] AS [t2]
    WHERE [t2].[CustomerID] = [t0].[CustomerID]
    ) AS [value]
FROM [CustomerInfo] AS [t0]
LEFT OUTER JOIN [OrderInfo] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
WHERE [t0].[CustomerID] = @p0
ORDER BY [t0].[CustomerID], [t1].[OrderID]

LEFT OUTER JOIN위를 주목하십시오 .


1

성능을 관리하십시오.

적어도 EF Core 에서는 여기에 주어진 다른 답변이 다른 성능을 초래할 수 있다는 것을 경험했습니다 . OP가 Linq to SQL에 대해 물었다는 것을 알고 있지만 EF Core에서도 동일한 질문이 발생하는 것으로 보입니다.

내가 처리해야 할 특정 사례에서 Marc Gravell의 (구문 적으로 더 좋은) 제안은 Mike U가 묘사 한 것과 유사하게 크로스 적용 내부에서 왼쪽 조인을 초래 하여이 특정 쿼리의 추정 ​​비용이 2라는 결과를 얻었습니다. 교차 조인이없는 쿼리에 비해 시간이 많이 걸립니다 . 서버 실행 시간 은 3 배로 다릅니다 . [1]

Marc Gravell의 솔루션으로 교차 조인이없는 쿼리가 발생했습니다.

컨텍스트 : 기본적으로 두 테이블에서 두 개의 왼쪽 조인을 수행해야했는데 각각의 테이블에는 다시 다른 테이블에 대한 조인이 필요했습니다. 또한 왼쪽 조인을 적용 해야하는 테이블에 다른 위치 조건을 지정해야했습니다. 또한 기본 테이블에 두 개의 내부 조인이있었습니다.

예상 운영자 비용 :

  • 크로스 적용 : 0.2534
  • 십자가없이 적용 : 0.0991.

서버 실행 시간 (ms) (쿼리가 10 번 실행되었으며 SET STATISTICS TIME ON을 사용하여 측정 된 쿼리) :

  • 크로스 적용 : 5, 6, 6, 6, 6, 6, 6, 6, 6, 6
  • 크로스 적용없이 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2

(처음 실행은 두 쿼리 모두에 대해 느려졌습니다. 캐시 된 것으로 보입니다.)

테이블 크기 :

  • 메인 테이블 : 87 행,
  • 왼쪽 조인의 첫 번째 테이블 : 179 행;
  • 왼쪽 조인의 두 번째 테이블 : 7 행

EF 코어 버전 : 2.2.1.

SQL Server 버전 : MS SQL Server 2017-14 ... (Windows 10).

모든 관련 테이블에는 기본 키에 대한 인덱스 만있었습니다.

내 결론 : 생성 된 SQL은 실제로 다를 수 있으므로 항상 보는 것이 좋습니다.


[1] 흥미롭게도 MS SQL Server Management Studio에서 '클라이언트 통계'를 설정할 때 반대 경향을 볼 수있었습니다. 즉, 교차 적용이없는 마지막 솔루션 실행에는 1 초 이상이 걸렸습니다. 내 설정에 문제가 있다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.