如何最优雅地将左连接与聚合 SQL 表达为 LINQ 查询
题
SQL:
SELECT
u.id,
u.name,
isnull(MAX(h.dateCol), '1900-01-01') dateColWithDefault
FROM universe u
LEFT JOIN history h
ON u.id=h.id
AND h.dateCol<GETDATE()-1
GROUP BY u.Id, u.name
解决方案
一种解决方案(尽管是将空值的处理推迟到代码中)可能是:
昨天的日期时间 = DateTime.Now.Date.AddDays(-1);
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
这不会产生完全相同的 SQL,但提供相同的逻辑结果。将“复杂”SQL 查询转换为 LINQ 并不总是那么简单。
其他提示
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
只需使用上面的代码,这应该可以正常工作!
这不是您的完整答案,但在左侧连接部分,您可以使用 DefaultIfEmpty 运算符,如下所示:
var collection =
from u in db.Universe
join history in db.History on u.id = history.id into temp
from h in temp.DefaultIfEmpty()
where h.dateCol < DateTime.Now.Date.AddDays(-1)
select u.id, u.name, h.dateCol ?? '1900-01-01'
我还不需要执行任何 groupby 命令,因此我将其省略,以免您走上错误的道路。另外两件事需要注意。我无法实际加入两个参数,尽管如上所述有一些方法可以解决它。另外,??运算符代替 SQL 中的 isnull 效果非常好。
你会想要使用 join into
构造以创建组查询。
TestContext db = new TestContext(CreateSparqlTripleStore());
var q = from a in db.Album
join t in db.Track on a.Name equals t.AlbumName into tracks
select new Album{Name = a.Name, Tracks = tracks};
foreach(var album in q){
Console.WriteLine(album.Name);
foreach (Track track in album.Tracks)
{
Console.WriteLine(track.Title);
}
}
不隶属于 StackOverflow