2014-03-28 78 views
0

如何编写LINQ查询来仅提取条件的边界记录。例如,考虑其代表跟踪从车辆接收到的数据下面的数据库表:LINQ查询设计

enter image description here

我想只获取记录47890和47880.这将给开始时间和结束时间的车辆停止时。

现在,在我的查询中,我获取所有记录,然后取第一个和最后一个。此外,查询需要是通用的,我可能有多个车辆停靠点。例如:

停止1:11:00 AM至1:00 PM

停止2:下午3:00至3:30 PM

等。

这是迄今为止我所编写的代码:下结果与LinqPad测试

var sData = db.Vehicles 
      .Where(v => v.VehicleId == vehicleId) 
      .SelectMany(v => v.GsmDeviceLogs) 
      .Where(gs => gs.DateTimeOfLog > startDate && gs.DateTimeOfLog < endDate && gs.Speed < zeroSpeed && !gs.IgnitionOn) 
      .Select(v => new 
      { 
       DateTimeOfLog = v.DateTimeOfLog, 
       Location = v.Location 
      }).OrderBy(gs => gs.DateTimeOfLog).ToList(); 
+0

您目前的查询是否返回错误的结果?我会在'!gs.IgnitionOn'(在第二个位置)之后提取开始和日期时间以及零速度的条件 - 这样您将只有零,并且您始终可以从第一个和最后一个条目结果查询。正如你所描述的那样,查询应该非常简单,你几乎就在那里。 – pasty

+0

但是,第一个也可能是最后一个。如果车辆每天停车两次,那么应该有2对First和Last。 –

+0

该查询起作用。但只会给我1首和最后一双。如果万一有两站。它将把它们合并成一个。我需要两个首先和最后一对两站。 –

回答

2

。它可以使用T-SQL进行优化并通过存储过程使用。

var indexedRowsAsc = arr.OrderBy(r => r.DateTimeOfLog) 
         .Select((r, index) => new { Row = r, Index = index}); 

// find intersection of current row and next row with condition (IgnitionOn) 
// intersection can ignore first and last row 
var foundRows = (from a in indexedRowsAsc 
       from b in indexedRowsAsc 
       where a.Index == (b.Index -1) && 
         a.Row.IgnitionOn != b.Row.IgnitionOn 
       select new {a, b} 
       ).ToArray(); 

var firstRow = arr.OrderBy(r => r.DateTimeOfLog).FirstOrDefault(); 
var lastRow = arr.OrderByDescending(r => r.DateTimeOfLog).FirstOrDefault(); 

// union found rows with first and last row 
var distinctFoundRows = foundRows.Select(fr => fr.a.Row) 
         // comparer can be added for union for proper distinct gathering 
         .Union(foundRows.Select(fr => fr.b.Row)) 
         // add first and last row 
         .Union(new Vehicle[]{firstRow}) 
         .Union(new Vehicle[]{lastRow}) 
         .Where(r => r!= null) 
         .OrderBy(r => r.DateTimeOfLog) 
         .ToArray(); 

// find result by grouping rows where IgnitionOn == 0 
int groupId = 1; 
var result = distinctFoundRows 
      .Select(row => new {Row =row, GroupId = (row.IgnitionOn == 0? groupId: ++groupId)}) 
      .Where(res => res.Row.IgnitionOn == 0) 
      .GroupBy(res => res.GroupId) 
      .Select(gr => new {First = gr.First().Row, Last = gr.Last().Row}) 
      .ToArray(); 

查找列中更改的值的秘诀是self joining

enter image description here