C# 如何协调LINQ中的第一条记录和最后一条记录
我的SQL数据库中有一个表,用于跟踪员工的进出时间。一张典型的唱片是这样的C# 如何协调LINQ中的第一条记录和最后一条记录,c#,.net,sql,linq,logic,C#,.net,Sql,Linq,Logic,我的SQL数据库中有一个表,用于跟踪员工的进出时间。一张典型的唱片是这样的 Id Device DateTime EmployeeId ------------------------------------------------------------------------- 1 InReader 2013/05/05 08:00:00
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
//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);
注意事项:-请注意,员工1有两条“InReader”记录,我想取较早的记录
-员工2有2条“OutReader”记录,我只想记录他最近的记录 如何使用LINQ协调输入和输出记录?(如果在LINQ中不可能,则使用TSQL)
类似于上面的内容应该可以实现这一点。使用
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()});
我向您提出了这个查询,并在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; }
}
我想你知道你员工的ID(或者你可能正在浏览一个列表)和你生成报告的日期,所以你需要做的第一件事就是用这样的东西获取你员工一天中的进出时间:
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
//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);
但这是否处理同一名员工的重复入境或出境记录?@PapyrusBit,代码被修改,并让我知道任何进一步的情况。那么,第二天添加入境记录时会发生什么情况?另外,如果一个人在一天内打卡,工作时间超过午夜,那又会怎样呢?也许最好在你的算法中加入这个设备。。有人忘记打卡,却打卡下班etc@PaulZahra,这是您必须实施的事情,因为您是了解所有业务案例的最佳人选,例如(a)如果员工未刷卡就从后门溜走会发生什么,或者(b)如果员工继续留在办公室会发生什么(如Christian Dietz所建议的)另一天。OP需要每天的输入/输出时间(这将给出每个员工在所有时间的第一个和最后一个记录,并且还假设这些记录是按日期时间排序的)。啊,是的。这需要对DateTime中的日期进行一些分组。此代码可能会引发错误,因为您使用的是
First()
和Last()
。我建议使用FirstOrDefault()
和lastorefault()
方法删除短语“类似的东西”,这是一个方向,而不是一个完整的解决方案记录只能保存一天吗?他们每晚都擦吗?