2013-06-21 58 views
2

我在我的SQL数据库中有一个表,用于跟踪员工的时间和时间。一个典型的记录看起来像这样如何调和LINQ中的第一个和最后一个记录

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就是一个自动递增列
设备是他们挖掘自己的员工卡上的设备,到时钟/或出
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)

+0

会记录只有一天?他们每晚都擦干净吗? –

回答

1

我给你做这个查询,并在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; } 
} 
+0

OP需要_daily_进/出时间(这将给每个员工的所有时间的第一个和最后一个记录,并且还假定记录按日期时间排序)。 –

+0

啊是的。这需要在DateTime中进行一些分组 –

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 
       } 

上面的东西应该做的伎俩。

+0

这段代码可能会因为使用First()和Last()而引发错误。我推荐使用'FirstOrDefault()'和'LastOrDefault()'方法 –

+0

,因此短语“类似那样”,它是一个方向推进,而不是一个完整的解决方案 –

0

使用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()}); 
+0

但是,这是否处理重复进入或退出记录雇员? –

+0

@PapyrusBit,代码被修改,并让我知道更多 – Nair

+0

那么当第二天添加条目时会发生什么?另外,如果一个人在一天钟钟并在午夜之后工作,该怎么办? – Dietz

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 }); 
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; 

你可以很容易地也为了通过雇员最近获得所有员工一天的时间,和过滤器重写此查询(这取决于什么是你的情况更好)。

之后,你可以从你的员工的进出一天的时候,你需要这样的报告的日期很容易地获得:

employeeDayInOut.Max(emp => emp.DateTime); 
    employeeDayInOut.Min(emp => emp.DateTime); 
相关问题