基于状态使用 group by 计算统计信息的问题

Problem in calculating statistics using group by based on statuses

我有如下数据:

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( "关闭").

非常感谢任何帮助:)

您似乎想要“每个 leaveupdatelog leaverequestid 月的最新状态”然后生成每个状态的统计信息,这对我来说意味着是两个分组。第一个分组剔除无趣的状态,第二个分组计算它们

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 集合(真的应该将 class 重命名为单数,classes 不应该有复数名称) 与数据一起:

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 group 只是将 X 记录的数据集分解为 Y 很多 Z 记录(其中 Y * Avg(Z) = X),因此您可以迭代每个 Y 并执行诸如“只取第一个 Z”之类的操作(这是我们首先做了什么)或“计算并连接所有 Z”(这是我们第二次做的)