C# LINQ到SQL按年龄分组
C#和VB.NET中的示例都可以 我有一个“People”表,其中包含以下列: -全名(nvarchar非空) -DOB(日期时间为空) 我想编写一个LINQ to SQL来按年龄对这些人进行分组,结果如下: 年龄19:4 ppl 20岁:5人 21岁:6人 等等 以下是我的尝试:C# LINQ到SQL按年龄分组,c#,vb.net,linq,linq-to-sql,C#,Vb.net,Linq,Linq To Sql,C#和VB.NET中的示例都可以 我有一个“People”表,其中包含以下列: -全名(nvarchar非空) -DOB(日期时间为空) 我想编写一个LINQ to SQL来按年龄对这些人进行分组,结果如下: 年龄19:4 ppl 20岁:5人 21岁:6人 等等 以下是我的尝试: Dim query = From ppl In db.People _ Select New With {.Age = DateTime.Now.Year - CDate(ppl.DOB).Year
Dim query = From ppl In db.People _
Select New With {.Age = DateTime.Now.Year - CDate(ppl.DOB).Year, .CountAge = ppl.Count}
请注意,表格中没有一些人的DOB记录,因此不应包括这些人。DOB列有这样的记录1982-10-2410:12:45AM,因为它是一个日期时间列
From ppl In db.People
Select New With {.Age = DateTime.Now.Year - CDate(ppl.DOB).Year,
.CountAge = ppl.Count()}
Group By (DateTime.Now.Year - CDate(ppl.DOB).Year)
我认为这个查询可以满足您的需要。假设DOB是一个可空的DateTime(DateTime?),那么没有DOB记录就意味着空:
from ppl in db.People
where ppl.DOB.HasValue
let age = DateTime.Today.Year - ppl.DOB.Value.Year
group ppl by age into ages
select new { Age=ages.Key, Persons = ages }
这在C#中,但由于语法相似,因此应该很好地转换为VB 这应该有效(并且应该更准确地计算年龄):
我宁愿:
var result = db.People
.Where(p => p.DOB != null) // exclude null DOB's from stats
.GroupBy(p => p.DOB.Value.Year)
.Select(g => new { Age = DateTime.Now.Year - g.Key, Count = g.Count() });
我们在这里按出生年份分组。这应该转化为SQL中的
groupbyyear(dob)
,与groupbyyear(GETDATE())-YEAR(dob)
相比,它的性能或优化性能稍好一些。几乎不可能将行表达式映射到索引中,但某些构造(如YEAR()
)可以单独进行优化,以部分使用日期时间索引。不过,我在这里做了很多假设,比如datetime
结构以年开始,SQL server关心year(x)
进行优化等。在构造LINQ查询时,最好记住这种情况。更准确的解决方案:
db.People.Where(p => p.DOB != null).GroupBy(p => ((DbFunctions.DiffDays(p.DOB, DateTime.Today) / 365)))
.Select(g => new {Age=g.Key, Count = g.Count()})
要将间隔分组,请执行以下操作:
var interval = 5; //years
db.People.Where(p => p.DOB != null).GroupBy(p => ((DbFunctions.DiffDays(p.DOB, DateTime.Today) / 365) / interval))
.Select(g => new {GroupIndex=g.Key, Count = g.Count()})
如果您使用的是EF Core 3.1 DbFunctions,则已将其替换为EF.Functions。 作为另一种选择,您可以使用:
var query = await db.People
.GroupBy(x.DateOfBirth.HasValue ? (int)(EF.Functions.DateDiffDay(x.DateOfBirth.Value, DateTime.UtcNow) / 365.25) : (int?)null)
.Select(x => new
{
Age = x.Key,
Count = x.Count(),
})
.ToListAsync(cancellationToken);
它考虑了“出生日期”,而不是时间,但比仅使用“出生年份”更准确。“注意,表格中有些人有DOB记录……”这句话中是否遗漏了一个词?应该是“有些人没有DOB记录”。是的,我没有打“否”这个词。Thx.对于初学者来说,有两个问题:
.Age=DateTime.Now.Year-CDate(ppl.DOB)。Year
在大多数情况下都会得到错误的年龄(考虑一年中出生日期的位置)。此外,这里根本没有聚合。如果两个人出生在1月和12月,他们在你的查询中是否仍然具有相同的年龄?事实上,这只是一个糟糕的近似值,但遵循OP使用的逻辑。他的问题是关于分组的,所以我想保持和他的一样:)
var query = await db.People
.GroupBy(x.DateOfBirth.HasValue ? (int)(EF.Functions.DateDiffDay(x.DateOfBirth.Value, DateTime.UtcNow) / 365.25) : (int?)null)
.Select(x => new
{
Age = x.Key,
Count = x.Count(),
})
.ToListAsync(cancellationToken);