У меня есть следующий запрос SQL, чтобы вернуть всех клиентов, у которых нет строк заказов без назначенных деталей - т.е. я хочу только клиентов, в которых каждая строка заказа каждого заказа не имеет назначенных частей - (в актуальная проблема Я имею дело с другим доменом, но перевёл клиентов / заказов для иллюстрации проблемы)
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 и Have. Я попытался заставить синтаксис LINQ Group By работать, но он продолжал помещать фильтр как WHERE, а не HAVING.
Есть идеи?
Изменить в ответ на ответы ниже:
Я принимаю ответ JamieSee, поскольку он решает указанную проблему, даже если он не создает запрос GROUP BY HAVING, который у меня изначально был.
Спасибо, Питер и Ник за ваш вклад в это. Я разработчик 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» в группу по «ключу», чтобы я мог ссылаться на нее из предложения Where, иначе компилятор не сможет увидеть эту переменную или любую другую переменную, появляющуюся перед группой. По пункту.
С указанным фильтром я получаю всех клиентов, у которых хотя бы в одном заказе есть строки без деталей, а не только у клиентов без деталей в любом заказе.