我有以下SQL查询来返回没有分配零件的OrderLines的所有客户 - 即我只希望每个订单的每个订单行没有分配零件的客户 - (在实际问题我正在处理不同的域,但已转换为客户/订单以说明问题)
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
我遇到的问题是我必须将“jl”推入Group By“Key”,以便我可以从Where子句中引用它,否则编译器无法看到该变量或该组之前出现的任何其他变量按条款。
根据指定的过滤器,我得到所有客户,其中至少有一个订单的行没有任何部分,而不是只有没有任何部件的客户。
答案 0 :(得分: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
。
答案 1 :(得分:0)
在没有生成的modlls(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
答案 2 :(得分: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
};