2013-06-21 60 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); 
相關問題