我有一个左外连接(下面)按预期返回结果。我需要将“右”表的结果限制为“第一次”命中。我能以某种方式这样做吗?目前,我得到两个表中每条记录的结果,我只想看左边表格中的一个结果(项目),无论我在右表中有多少结果(照片)。
var query = from i in db.items
join p in db.photos
on i.id equals p.item_id into tempPhoto
from tp in tempPhoto.DefaultIfEmpty()
orderby i.date descending
select new
{
itemName = i.name,
itemID = i.id,
id = i.id,
photoID = tp.PhotoID.ToString()
};
GridView1.DataSource = query;
GridView1.DataBind();
答案 0 :(得分:59)
这将为你完成这项工作。
from i in db.items
let p = db.photos.Where(p2 => i.id == p2.item_id).FirstOrDefault()
orderby i.date descending
select new
{
itemName = i.name,
itemID = i.id,
id = i.id,
photoID = p == null ? null : p.PhotoID.ToString();
}
当我针对自己的模型生成它时,我得到了这个sql(并且在投影中没有名称和第二个id列。)
SELECT [t0].[Id] AS [Id], CONVERT(NVarChar,(
SELECT [t2].[PhotoId]
FROM (
SELECT TOP (1) [t1].[PhotoId]
FROM [dbo].[Photos] AS [t1]
WHERE [t1].[Item_Id] = ([t0].[Id])
) AS [t2]
)) AS [PhotoId]
FROM [dbo].[Items] AS [t0]
ORDER BY [t0].[Id] DESC
当我询问该计划时,它显示子查询是通过此连接实现的:
<RelOp LogicalOp="Left Outer Join" PhysicalOp="Nested Loops">
答案 1 :(得分:4)
您可以执行以下操作:
var q = from c in
(from s in args
select s).First()
select c;
围绕查询的最后部分。不确定它是否会起作用或它将产生什么样的恶意SQL:)
答案 2 :(得分:3)
您要做的是对表格进行分组。最好的方法是:
var query = from i in db.items
join p in (from p in db.photos
group p by p.item_id into gp
where gp.Count() > 0
select new { item_id = g.Key, Photo = g.First() })
on i.id equals p.item_id into tempPhoto
from tp in tempPhoto.DefaultIfEmpty()
orderby i.date descending
select new
{
itemName = i.name,
itemID = i.id,
id = i.id,
photoID = tp.Photo.PhotoID.ToString()
};
编辑:这是David B说的。我只是这样做,因为尼克问我。尼克,请根据您的需要修改或删除此部分。
生成的SQL非常大。 int 0(与计数进行比较)通过参数传递。
SELECT [t0].X AS [id], CONVERT(NVarChar(MAX),(
SELECT [t6].Y
FROM (
SELECT TOP (1) [t5].Y
FROM [dbo].[Photos] AS [t5]
WHERE (([t4].Y IS NULL) AND ([t5].Y IS NULL)) OR (([t4].Y IS NOT NULL) AND ([t5].Y IS NOT NULL) AND ([t4].Y = [t5].Y))
) AS [t6]
)) AS [PhotoId]
FROM [dbo].[Items] AS [t0]
CROSS APPLY ((
SELECT NULL AS [EMPTY]
) AS [t1]
OUTER APPLY (
SELECT [t3].Y
FROM (
SELECT COUNT(*) AS [value], [t2].Y
FROM [dbo].[Photos] AS [t2]
GROUP BY [t2].Y
) AS [t3]
WHERE (([t0].X) = [t3].Y) AND ([t3].[value] > @p0)
) AS [t4])
ORDER BY [t0].Z DESC
执行计划显示三个左连接。至少有一个是微不足道的,不应该被计算(它带来零)。这里有足够的复杂性,我无法明确指出任何效率问题。它可能运行得很好。
答案 3 :(得分:0)
使用内部查询。对于没有照片的情况,请包括DefaultIfEmpty
;对于多个照片的情况,请包括orderby
。以下示例以最大的id
拍摄照片。
var query =
from i in db.items
let p = from p in db.photos where i.id == p.item_id orderby p.id select p).DefaultIfEmpty().Last()
orderby i.date descending
select new {
itemName = i.name,
itemID = i.id,
id = i.id,
photoID = p.PhotoID
};
如果需要专门处理没有照片的情况,则可以省略DefaultIfEmpty
并改用FirstOrDefault
/ LastOrDefault
。