2009-08-15 2 views
1

내가 필요한 것은 그렇게 간단하고 쉬운 쿼리입니다. LINQ에서이 작업을 얼마나 많은 노력을 기울여야 하는지를 알려주지 않습니다. T-SQL에서는 다음과 같습니다LINQ 집계는 SQL CE에 왼쪽 가입

var invoices = (
    from I in Invoices 
    where I.Date >= start && 
      I.Date <= end 
    join P in Payments on I.InvoiceID equals P.InvoiceID into payments 
    select new{ 
     I.InvoiceID, I.CustomerID, AmountInvoiced = I.Amount, InvoiceDate = I.Date, 
     AmountPaid = ((decimal?)payments.Select(P=>P.Amount).Sum()).GetValueOrDefault(), 
     AmountDue = I.Amount - ((decimal?)payments.Select(P=>P.Amount).Sum()).GetValueOrDefault() 
    } 
).OrderByDescending(row=>row.AmountDue); 

이 실행시 상응하는 결과 세트를 가져옵니다

SELECT I.InvoiceID, I.CustomerID, I.Amount AS AmountInvoiced, 
     I.Date AS InvoiceDate, ISNULL(SUM(P.Amount), 0) AS AmountPaid, 
     I.Amount - ISNULL(SUM(P.Amount), 0) AS AmountDue 
FROM Invoices I 
LEFT JOIN Payments P ON I.InvoiceID = P.InvoiceID 
WHERE I.Date between @start and @end 
GROUP BY I.InvoiceID, I.CustomerID, I.Amount, I.Date 
ORDER BY AmountDue DESC 

내가 함께 왔어요 가장 좋은 등가 LINQ 표현은 할 훨씬 더 오래 걸렸다 SQL Server에 대해. 그러나 SQL CE 데이터베이스를 사용하면 작업이 변경됩니다. T-SQL은 거의 동일합니다. 나는 ISNULLCOALESCE으로 바꾸면됩니다. 같은 LINQ 식을 사용하지만, 오류가 발생합니다

There was an error parsing the query. [ Token line number = 4, 
Token line offset = 9,Token in error = SELECT ]

그래서 우리는 생성 된 SQL 코드를 보면 :

SELECT [t3].[InvoiceID], [t3].[CustomerID], [t3].[Amount] AS [AmountInvoiced], [t3].[Date] AS [InvoiceDate], [t3].[value] AS [AmountPaid], [t3].[value2] AS [AmountDue] 
FROM (
    SELECT [t0].[InvoiceID], [t0].[CustomerID], [t0].[Amount], [t0].[Date], COALESCE((
     SELECT SUM([t1].[Amount]) 
     FROM [Payments] AS [t1] 
     WHERE [t0].[InvoiceID] = [t1].[InvoiceID] 
     ),0) AS [value], [t0].[Amount] - (COALESCE((
     SELECT SUM([t2].[Amount]) 
     FROM [Payments] AS [t2] 
     WHERE [t0].[InvoiceID] = [t2].[InvoiceID] 
     ),0)) AS [value2] 
    FROM [Invoices] AS [t0] 
    ) AS [t3] 
WHERE ([t3].[Date] >= @p0) AND ([t3].[Date] <= @p1) 
ORDER BY [t3].[value2] DESC 

우를! SQL 서버에 대해 실행할 때보기 흉하고 비효율적이지만 으로 가정하면 걱정하지 않아도됩니다.쓰기가 더 짧고 성능 차이는 그다지 커야합니다. 그러나 그것은 단지을 SQL CE에 대해 작동시키지 않으며, 분명히 SELECT 목록 내의 하위 쿼리를 지원하지 않습니다.

사실 LINQ에서 몇 가지 다른 왼쪽 조인 쿼리를 시도했으며 모두 동일한 문제가있는 것으로 보입니다. 심지어 :

from I in Invoices 
join P in Payments on I.InvoiceID equals P.InvoiceID into payments 
select new{I, payments} 

를 생성 : 또한 오류가 발생

SELECT [t0].[InvoiceID], [t0].[CustomerID], [t0].[Amount], [t0].[Date], [t1].[InvoiceID] AS [InvoiceID2], [t1].[Amount] AS [Amount2], [t1].[Date] AS [Date2], (
    SELECT COUNT(*) 
    FROM [Payments] AS [t2] 
    WHERE [t0].[InvoiceID] = [t2].[InvoiceID] 
    ) AS [value] 
FROM [Invoices] AS [t0] 
LEFT OUTER JOIN [Payments] AS [t1] ON [t0].[InvoiceID] = [t1].[InvoiceID] 
ORDER BY [t0].[InvoiceID] 

을 :

There was an error parsing the query. [ Token line number = 2, 
Token line offset = 5,Token in error = SELECT ]

그래서 LINQ를 사용하여 SQL CE 데이터베이스에 가입하는 간단한 왼쪽을 할 수 있습니까? 내 시간을 낭비하고 있니?

답변

3

group by 인 T-SQL 버전에 가까운 쿼리 식을 사용해 보셨습니까?

var Invoices = new[] { 
    new { InvoiceID = 1, CustomerID = 2, Amount = 2.5m, Date = DateTime.Today }, 
    new { InvoiceID = 2, CustomerID = 3, Amount = 5.5m, Date = DateTime.Today } 
}.AsQueryable(); 
var Payments = new[] { 
    new { InvoiceID = 1, Amount = 1m } 
}.AsQueryable(); 

수익률 : 결과는 바로 메모리 컬렉션에 보이는

var invoices = 
    from I in Invoices 
    where I.Date >= start && I.Date <= end 
    join P in Payments on I.InvoiceID equals P.InvoiceID into J 
    group J.Sum(p => p.Amount) by new { I.InvoiceID, I.CustomerID, I.Amount, I.Date } into G 
    let AmountPaid = G.Sum() 
    let AmountDue = G.Key.Amount - AmountPaid 
    orderby AmountDue descending 
    select new 
    { 
     G.Key.InvoiceID, 
     G.Key.CustomerID, 
     AmountInvoiced = G.Key.Amount, 
     InvoiceDate = G.Key.Date, 
     AmountPaid, 
     AmountDue 
    }; 

{ InvoiceID = 2, CustomerID = 3, AmountInvoiced = 5.5, InvoiceDate = 8/15/2009, 
    AmountPaid = 0, AmountDue = 5.5 } 
{ InvoiceID = 1, CustomerID = 2, AmountInvoiced = 2.5, InvoiceDate = 8/15/2009, 
    AmountPaid = 1, AmountDue = 1.5 } 

문제가 해결되지 않는 경우는 LINQ는 일반적으로 조인에 DefaultIfEmpty()를 사용하여 가입 왼쪽 결과. 다음과 같이 대신해야 할 수도 있습니다.

var invoices = 
    from I in Invoices 
    where I.Date >= start && I.Date <= end 
    join P in Payments on I.InvoiceID equals P.InvoiceID into J 
    from PJ in J.DefaultIfEmpty() // Left Join 
    group PJ by new { I.InvoiceID, I.CustomerID, I.Amount, I.Date } into G 
    let AmountPaid = G.Sum(p => p == null ? 0 : p.Amount) 
    // etc... 
+0

'DefaultIfEmpty()'가없는 첫 번째 해결책은 필자의 예제와 비슷한 오류로 폭발합니다. 두 번째 예제가 작동합니다! 고맙습니다! 나는 다른 왼쪽 결합 시도에서도이 기술을 시도 할 것이다. –