Sql server 如何使用Linq to Sql计算一天中的空闲工作时间?

Sql server 如何使用Linq to Sql计算一天中的空闲工作时间?,sql-server,linq,Sql Server,Linq,例如,我有一个任务MIS,数据是: Id用户任务TaskStartTime TaskFinishTime 迈克任务2009-07-2809:00:00 2009-07-2809:45:00 迈克任务2009-07-2809:30:00 2009-07-2809:40:00 迈克任务2009-07-2809:50:00 2009-07-2810:30:00 迈克任务2009-07-2810:20:00 2009-07-2810:30:00 迈克任务2009-07-2810:40:00 2009-0

例如,我有一个任务MIS,数据是:

Id用户任务TaskStartTime TaskFinishTime

迈克任务2009-07-2809:00:00 2009-07-2809:45:00

迈克任务2009-07-2809:30:00 2009-07-2809:40:00

迈克任务2009-07-2809:50:00 2009-07-2810:30:00

迈克任务2009-07-2810:20:00 2009-07-2810:30:00

迈克任务2009-07-2810:40:00 2009-07-2811:50:00

如何使用LINQtoSQL计算一天(如2009-07-28)的空闲时间

结果应该是:

5分钟(任务1、任务2和任务3之间)+10分钟(任务4和任务5之间)

=15分钟类似这样的时间

假设您有一组任务对象:

public class Task
{
    public Guid ID { get; set; }
    public string User { get; set; }
    public string Task { get; set; }
    public DateTime TaskStartTime { get; set; }
    public DateTime TaskFinishTime { get; set; }
}

var tasks = new List<Task> ();
// Fill tasks here...

var idleTimeInMinutes =
    tasks.Last ().TaskFinishTime.Subtract (tasks.First ().TaskStartTime).Minutes
    - tasks.Sum (t => t.TaskFinishTime.Subtract (t.TaskStartTime).Minutes);
公共类任务
{
公共Guid ID{get;set;}
公共字符串用户{get;set;}
公共字符串任务{get;set;}
公共日期时间任务开始时间{get;set;}
公共日期时间任务FinishTime{get;set;}
}
var tasks=newlist();
//在这里填写任务。。。
var idleTimeInMinutes=
tasks.Last().TaskFinishTime.Subtract(tasks.First().TaskStartTime).Minutes
-tasks.Sum(t=>t.TaskFinishTime.Subtract(t.TaskStartTime.Minutes);

编辑:现在,等等,我在您的示例中看到任务重叠。那我写的东西就行不通了。我得考虑一下……

好吧,我已经想出了一个可行的办法

您可以使用以下选项:

from a in Tasks
join b in Tasks on true equals true
where a.TaskStartTime < b.TaskFinishTime
where a.TaskFinishTime > b.TaskStartTime
where a.Id < b.Id
select new {
    Id = a.Id,
    User = a.User,
    Task = (a.Task + " + " + b.Task),
    TaskStartTime = (a.TaskStartTime < b.TaskStartTime ? a.TaskStartTime : b.TaskStartTime),
    TaskFinishTime = (a.TaskFinishTime > b.TaskFinishTime ? a.TaskFinishTime : b.TaskFinishTime)
 }
来自任务中的
在true等于true的任务中加入b
其中a.TaskStartTimeb.TaskStartTime
其中a.Idb.TaskFinishTime?a.TaskFinishTime:b.TaskFinishTime)
}

要分解单个任务,直到没有交叉点,只需将所有时间之和减去所有任务中的时间之和。

将感兴趣的记录拉入内存并在内存中进行处理(通过将重叠范围分解为单个范围)。折叠任务不适用于查询方法,例如sql或linqtosql。

下面是一些使用Linq完成此工作的代码。我不知道它是否是你想要的形式,但逻辑与你给我们的数据是一致的。你应该能够将它重新排列成适合你的应用程序的形状

已修改

var rows = new[] { 
    new { Id =  1, Name="Mike", TaskName="task1", StartTime=DateTime.Parse("2009-07-28 09:00:00"), EndTime=DateTime.Parse("2009-07-28 09:45:00") },
    new { Id =  2, Name="Mike", TaskName="task2", StartTime=DateTime.Parse("2009-07-28 09:30:00"), EndTime=DateTime.Parse("2009-07-28 09:40:00") },
    new { Id =  3, Name="Mike", TaskName="task3", StartTime=DateTime.Parse("2009-07-28 09:50:00"), EndTime=DateTime.Parse("2009-07-28 10:30:00") },
    new { Id =  4, Name="Mike", TaskName="task4", StartTime=DateTime.Parse("2009-07-28 10:20:00"), EndTime=DateTime.Parse("2009-07-28 10:30:00") },
    new { Id =  5, Name="Mike", TaskName="task5", StartTime=DateTime.Parse("2009-07-28 10:40:00"), EndTime=DateTime.Parse("2009-07-28 11:50:00") },
        };

var ranges = rows.Select(x => new { StartTime = x.StartTime, EndTime = x.EndTime });
int rangeCount = 0;
while (ranges.Count() != rangeCount)
{
    rangeCount = ranges.Count();
    ranges = ranges.Select(x => new {
        StartTime = ranges.Where(y => (y.StartTime <= x.StartTime && y.EndTime >= x.StartTime) || (y.StartTime <= x.EndTime && y.EndTime >= x.EndTime)).Min(y => y.StartTime),
        EndTime = ranges.Where(y => (y.StartTime <= x.StartTime && y.EndTime >= x.StartTime) || (y.StartTime <= x.EndTime && y.EndTime >= x.EndTime)).Max(y => y.EndTime),
    }).Distinct().ToList();  // ToList required to avoid recursion issues
}

TimeSpan gapTime = ranges.Max(x => x.EndTime) - ranges.Min(x => x.StartTime) - new TimeSpan(ranges.Sum(x => (x.EndTime - x.StartTime).Ticks));

System.Diagnostics.Trace.WriteLine(gapTime);
var rows=new[]{
新的{Id=1,Name=“Mike”,TaskName=“task1”,StartTime=DateTime.Parse(“2009-07-28 09:00:00”),EndTime=DateTime.Parse(“2009-07-28 09:45:00”),
新的{Id=2,Name=“Mike”,TaskName=“task2”,StartTime=DateTime.Parse(“2009-07-28 09:30:00”),EndTime=DateTime.Parse(“2009-07-28 09:40:00”),
新的{Id=3,Name=“Mike”,TaskName=“task3”,StartTime=DateTime.Parse(“2009-07-28 09:50:00”),EndTime=DateTime.Parse(“2009-07-28 10:30:00”),
新的{Id=4,Name=“Mike”,TaskName=“task4”,StartTime=DateTime.Parse(“2009-07-28 10:20:00”),EndTime=DateTime.Parse(“2009-07-28 10:30:00”),
新的{Id=5,Name=“Mike”,TaskName=“task5”,StartTime=DateTime.Parse(“2009-07-28 10:40:00”),EndTime=DateTime.Parse(“2009-07-28 11:50:00”),
};
var ranges=rows.Select(x=>new{StartTime=x.StartTime,EndTime=x.EndTime});
int rangeCount=0;
while(ranges.Count()!=rangeCount)
{
rangeCount=ranges.Count();
范围=范围。选择(x=>新建{
StartTime=范围。其中(y=>(y.StartTime=x.StartTime)| |(y.StartTime=x.EndTime)).Min(y=>y.StartTime),
EndTime=范围。其中(y=>(y.StartTime=x.StartTime)| |(y.StartTime=x.EndTime)).Max(y=>y.EndTime),
}).Distinct().ToList();//避免递归问题所需的ToList
}
TimeSpan gapTime=ranges.Max(x=>x.EndTime)-ranges.Min(x=>x.StartTime)-newtimespan(ranges.Sum(x=>x.EndTime-x.StartTime.Ticks));
系统诊断跟踪写入线(gapTime);

如果task1数据为:StartTime=2009-07-28 09:00:00 EndTime=2009-07-28 09:50:00,则结果是错误的。我看到了问题所在。使用上面的代码,您将需要递归地计算范围,直到不能减少范围为止。希望在几个小时后我能再做一次之后,我会有一个更好的版本。我最近的编辑添加了一个循环,它递归地合并范围,直到只剩下合适的项目。这将处理您向其抛出的任何数据。如果task1为:start=2009-07-28 09:00:00 end=2009-07-28 09:51:00,则结果有误。这将使task1和task2类似于:“task1+task2”、“2009-07-28 09:00:00”、“2009-07-28 09:45:00”。我想如果任务1是:开始=2009-07-28 09:00:00结束=2009-07-28 09:51:00,那么结果应该是任务1+task3,跳过任务2-1。这听起来像是一个家庭作业问题,而且你还没有给出证据证明你有能力自己解决它。