3

我的 SQL 数据库中有一个表,用于跟踪员工的上班时间和下班时间。典型的记录如下所示

Id           Device               DateTime                    EmployeeId    
-------------------------------------------------------------------------
1            InReader             2013/05/05 08:00:00         1
2            InReader             2013/05/05 08:00:05         1
3            InReader             2013/05/05 08:01:00         2
4            InReader             2013/05/05 08:02:00         3
5            InReader             2013/05/05 08:03:00         4
6            OutReader            2013/05/05 17:00:00         1
7            OutReader            2013/05/05 17:05:05         2
8            OutReader            2013/05/05 17:05:10         2
9            OutReader            2013/05/05 17:10:00         3
10           OutReader            2013/05/05 17:30:00         4

Id 只是一个自动增量列
Device 是他们点击员工卡的设备,用于打卡/打卡
DateTime 是他们点击员工卡的时间

我想知道,在一天结束时,当我生成报告时,我怎样才能协调他们的及时与超时,使得输出可能如下所示:

Employee Id            In time                    Out time
-----------------------------------------------------------------------
1                      2013/05/05 08:00:00        2013/05/05 17:00:00
2                      2013/05/05 08:01:00        2013/05/05 17:05:10
3                      2013/05/05 08:02:00        2013/05/05 17:10:00
4                      2013/05/05 08:03:00        2013/05/05 17:30:00

注意事项:
- 请注意,员工 1 有 2 条“InReader”记录,我想记录较早的记录
- 员工 2 有 2 条“OutReader”记录,我只想记录他的最新记录

如何使用 LINQ 协调 IN 和 OUT 记录?(或 TSQL,如果在 LINQ 中不可能)

4

5 回答 5

2

我向您提出了这个查询,并在 LinqPad 中进行了测试。我会给你完整的代码,你可以自己试试。

查询本身:

tracks.GroupBy(x => x.EmployeeId)
      .Select(x => new 
            {
                EmployeeId = x.Key,
                InTime = x.FirstOrDefault(y => y.Device.Equals("InReader")).DateTime,
                OutTime = x.LastOrDefault(y => y.Device.Equals("OutReader")).DateTime
            })

完整的代码示例:

void Main()
{
    var tracks = new[]
    {
        new Track{Id = 1, Device = "InReader", DateTime = new DateTime(2013,5,5,8,0,0), EmployeeId = 1},
        new Track{Id = 2, Device = "InReader", DateTime = new DateTime(2013,5,5,8,0,5), EmployeeId = 1},
        new Track{Id = 3, Device = "InReader", DateTime = new DateTime(2013,5,5,8,1,0), EmployeeId = 2},
        new Track{Id = 4, Device = "InReader", DateTime = new DateTime(2013,5,5,8,2,0), EmployeeId = 3},
        new Track{Id = 5, Device = "InReader", DateTime = new DateTime(2013,5,5,8,3,0), EmployeeId = 4},

        new Track{Id = 6, Device = "OutReader", DateTime = new DateTime(2013,5,5,17,0,0), EmployeeId = 1},
        new Track{Id = 7, Device = "OutReader", DateTime = new DateTime(2013,5,5,17,5,5), EmployeeId = 2},
        new Track{Id = 8, Device = "OutReader", DateTime = new DateTime(2013,5,5,17,5,10), EmployeeId = 2},
        new Track{Id = 9, Device = "OutReader", DateTime = new DateTime(2013,5,5,17,10,0), EmployeeId = 3},
        new Track{Id = 10, Device = "OutReader", DateTime = new DateTime(2013,5,5,17,30,0), EmployeeId = 4},
    };

        // the Query
        tracks
    .GroupBy(x => x.EmployeeId)
    .Select(x => new 
        {
            EmployeeId = x.Key,
            InTime = x.FirstOrDefault(y => y.Device.Equals("InReader")).DateTime,
            OutTime = x.LastOrDefault(y => y.Device.Equals("OutReader")).DateTime
        })
}

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

    public string Device { get; set; }

    public DateTime DateTime { get; set; }

    public int EmployeeId { get; set; }
}
于 2013-06-21T08:14:03.840 回答
1

使用Min, Max聚合返回序列中的最小或最大元素并GroupBy用于排序。

var result=YourTableRowCollection.GroupBy(x=>x.EmployeeId)
                            .Select(x=>new { EmployeeId=x.Key,
                                             InTime=x.Min(t=>DateTime.Parse(t.InTime)).ToString(),
                                             OutTime=x.Max(t=>DateTime.Parse(t.OutTime)).ToString()});
于 2013-06-21T07:54:32.507 回答
0
var result = table.Where(e => e.Device == "InReader")
                    .GroupBy(e => e.EmployeeId)
                        .Select(g => g.OrderBy(d => d.DateTime).First())
            .Join(
            table.Where(e => e.Device == "OutReader")
                    .GroupBy(e => e.EmployeeId)
                        .Select(g => g.OrderByDescending(d => d.DateTime).First()), 
            t => t.EmployeeId, t => t.EmployeeId,(t, i) => new { Id = t.EmployeeId, In = t.DateTime, Out = i.DateTime });
于 2013-06-21T08:05:38.133 回答
0
 var x = from current in context.Employess
                let firstRecord = current.Where(c=> c.Track.Device == "InReader").OrderBy(c => c.DateTime).First()
                let lastRecord = current.Where(c=> c.Track.Device == "OutReader").OrderBy(c => c.DateTime).Last()
                select{
                    // do something
                }

像上面这样的东西应该可以解决问题。

于 2013-06-21T07:45:46.887 回答
0

我想您知道您的员工的 ID(或者您可能正在查看一个列表)以及您生成报告的日期,所以您需要做的第一件事就是让您的员工在一天中的进出时间与某事。像这样:

 //first second of the day
 DateTime firstSecondOfTheDay = dateToCheck.Subtract(dateToCheck.TimeOfDay);
 //last second of the day 
 TimeSpan endOfDay = new TimeSpan(23, 59, 59);
 DateTime lastSecondOfTheDay = firstSecondOfTheDay.Add(endOfDay);
 var employeeDayInOut = from emp in context.Employess
                        where (emp.DateTime >= firstSecondOfTheDay) &
                              (emp.DateTime <= lastSecondOfTheDay) &
                              (emp.EmployeeId == idToCheck)
                        select emp;

您还可以轻松地重写此查询以获取一天中的所有员工时间,并最近按 EmployeeId 过滤(这取决于您的情况更好)。

之后,您可以轻松地从您的员工一天中的进出时间获取您需要的报告日期,如下所示:

  employeeDayInOut.Max(emp => emp.DateTime);
  employeeDayInOut.Min(emp => emp.DateTime);
于 2013-06-21T08:16:18.913 回答