【问题标题】:Problem in calculating statistics using group by based on statuses基于状态使用 group by 计算统计信息的问题
【发布时间】:2021-04-28 22:08:16
【问题描述】:

我有如下数据:

Table : LeaveRequest

Id    DepartmentId
1     100

Table: LeaveUpdateLogs

Id      RequestedDate             LeaveRequestId     Status
1       2020-01-26 11:55:56       1                  Pending
2       2020-02-24 10:55:56       1                  Accepted
3       2020-02-24 11:55:56       1                  Accepted
4       2020-03-01 09:55:56       1                  Declined
5       2020-03-27 10:55:56       1                  Closed

6       2020-01-09 05:55:56       2                  Pending
6       2020-02-09 05:55:56       2                  Accepted
7       2020-05-12 02:55:56       2                  Accepted
8       2020-06-14 05:55:56       2                  Declined
9       2020-06-15 05:55:56       2                  Closed 

我想计算Start date and EndDate 之间的统计信息,并想计算每个状态的统计信息。

预期输出:开始日期 = 01-01-2020 结束日期 = 06-30-2020

Pending =  2 (2020-01-26 11:55:56,2020-01-09 05:55:56)
Accepted = 3 (2020-02-24 11:55:56,2020-02-09 05:55:56,2020-05-12 02:55:56)
Declined = 0
Closed = 2 (2020-03-27 10:55:56, 2020-06-15 05:55:56)

类:

public class LeaveRequest 
    {

        public int Id { get; set; }
        
        public int DepartmentId { get; set; }

        public virtual ICollection<LeaveUpdateLogs> LeaveUpdateLogs { get; set; }

    }
    
    public class LeaveUpdateLogs 
    {
    
        public int Id { get; set; }

        public DateTimeOffset RequestedDate { get; set; }
        
        public int LeaveRequestId { get; set; }
        
        public string Status { get; set; }

        public virtual LeaveRequest LeaveRequest { get; set; }

    }

查询:

var query = from l in context.LeaveUpdateLogs
            where l.LeaveRequest.DepartmentId == 100 &&
            (l.RequestedDate >= fromDate && l.RequestedDate < toDate)

对我来说唯一的挑战是计算同一个月和同一 LeaveRequestId 的数据。例如:

Id      RequestedDate             LeaveRequestId     Status
4       2020-03-01 09:55:56       1                  Declined
5       2020-03-27 10:55:56       1                  Closed

对于上述数据,我们在同一个月有 2 个状态,对于相同的 LeaveRequestId 即 1,但我想考虑该月的最后日期(“2020-03-27”)并为该状态增加 1(“关闭")。

我将非常感谢任何帮助:)

【问题讨论】:

  • 我希望您的查询包含 group by,,
  • @CaiusJard 是的,我同意,但问题是如果我按“LeaveRequestId”分组,那么我将无法计算我在预期输出中提到的所有状态的统计信息。所以这就是问题所在。我可能会像这样将 group by "group l by 1 into g" 伪装成这样,但是我不知道这个月我会做什么。如果您能详细说明按什么分组,我将不胜感激

标签: c# entity-framework linq entity-framework-6


【解决方案1】:

看起来您想要“每个 leaveupdatelog leaverequestid-month 的最新状态”然后生成每个状态的统计信息,这对我来说是两个分组。第一个分组剔除无趣的状态,第二个分组统计它们

var interesting = query.GroupBy(lul => new{lul.LeaveRequestId, D=new DateTime(lul.RequestedDate.Year, lul.RequestedDate.Month, 1)})
    .Select(g => g.OrderByDescending(gg => gg.RequestedDate).First());

这会按 ID 和请求日期的月份对数据进行分组。这意味着您得到的组有两个成员分别代表 2,3 和 4,5 和 8,9,然后只选择最新日期的一个,删除 2,4,8

然后我们可以对剩余部分进行另一个分组

var stats = interesting.GroupBy(lul => lul.Status);

这实现了一个集合,其中 stats 中的每个项目都有一个状态键和一个带有数据的 leaveupdatelogs 集合(应该真正将该类重命名为单数,类不应该有复数名称):

foreach(var g in stats)
    Console.WriteLine($"{g.Key} = {g.Count} ({string.Join(',', g.Select(gg => gg.RequestedDate))}");

应该产生您期望的输出,除了没有 Declined 因此不会为它们打印任何内容。如果重要的是不要让他们“通知他们缺席”,那么也许考虑另一种操作来揭示他们,例如

someArrayOfAllStatus.Except(stats.Select(g=>g.Key))

您可以从枚举本身或原始查询(使用 select/distinct)生成所有状态的数组,具体取决于枚举中是否存在您不想显示的其他状态,因为它们不在查询中

重要的是要记住 LINQ 组与 sql 组不同。在 sql 中,您必须指定聚合并丢弃数据,因为没有 SELECT 就不能拥有 GROUP BY。在 LINQ 中,您可以,因此组操作实际上形成了键控存储桶并将所有数据作为集合放入其中,因此在任何步骤中,所有原始数据都可以进行操作。换句话说,LINQ 组只是将 X 记录的数据集分解为 Y 多个 Z 记录(其中 Y * Avg(Z) = X),因此您可以迭代每个 Y 并执行诸如“仅取第一个 Z”之类的操作(即我们首先做了什么)或“count and stringjoin all the Z”(这是我们第二个做的)

【讨论】:

  • 赞成您为帮助我所做的努力,但带有“except”功能的 linq 查询将在实体框架中工作?
  • Except 是一个 LINQ 的东西和一个 SQL 的东西(SELECT 1 EXCEPT SELECT 1 没有给出任何行)所以我希望它们被映射了.. 不过我会说要小心;如果 Status 的值在代码中的枚举中可用,我个人认为冒着用昂贵的集合减少操作打扰 db 的风险没有任何意义,例如,您可以将统计信息转换为哈希集或字典,然后添加任何值在你枚举它之前,枚举的数量还不存在
  • 这听起来是个好主意,但实际上并没有完全理解。您是否介意详细说明 hast set 或字典的想法,或者如果您可以提供示例,那么学习新东西并实施它对我来说会很棒。我会很感激的。
  • 例如,如果你做了var d = stats.ToDictionary(),你会有一个“状态=>(休假更新日志的集合)”的字典,然后你可以枚举foreach(var s in new []{"Declined","Accepted",...})并在循环内做@987654328 @ 为未表示的任何状态插入空集合,例如“拒绝”
  • 不应该是它不可用,只是我没有选择重载-stats.ToDictionary(s =&gt; s.Key)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
相关资源
最近更新 更多