在Linq按时间范围分组

时间:2009-08-17 15:13:11

标签: c# .net linq

我今天第一次陷入某些linq查询,我正在努力解决一些比较复杂的问题。我正在构建一个查询来从表中提取数据以构建图形。我感兴趣的表格列是 Id 时间

用户将选择开始时间,结束时间和要绘制的间隔(点)数。值列将针对每个间隔进行平均。

我可以使用每个间隔的linq请求执行此操作,但我正在尝试在一个查询中编写它,所以我只需要去一次数据库。

到目前为止,我有:

var timeSpan = endTime.Subtract(startTime);
var intervalInSeconds = timeSpan.TotalSeconds / intervals;

var wattList = (from t in _table
                where t.Id == id
                    && t.Time >= startTime
                    && t.Time <= endTime
                group t by  intervalInSeconds // This is the bit I'm struggling with
                    into g
                    orderby g.Key 
                    select g.Average(a => a.Value))
                ).ToList();

欢迎任何有关时间范围分组的帮助。

3 个答案:

答案 0 :(得分:1)

我自己也是这样做的,因为你描述的情况完全相同。

对于速度,修改数据库的datapoints表以包含基于整数的时间列SecondsSince2000,然后在我的LINQ to SQL查询中使用该值。 SecondsSince2000是计算列,定义为:

datediff(second, dateadd(month,1200,0), DataPointTimeColumn) PERSISTED

其中DataPointTimeColumn是存储数据点时间的列的名称。魔术函数dateadd(month,1200,0)在午夜返回2000-01-01,因此该列存储自该时间以来的秒数。

然后,LINQ to SQL查询变得更加简单,更快:

int timeSlotInSeconds = 60;

var wattList = 
    (from t in _table
     where t.Id == id
           && t.Time >= startTime
           && t.Time <= endTime
     group t by t.SecondsSince2000 - (t.SecondsSince2000 % timeSlotInSeconds)
     into g
     orderby g.Key 
     select g.Average(a => a.Value))).ToList();

如果您无法修改数据库,您仍然可以执行此操作:

var baseTime = new DateTime(2000, 1, 1);

var wattList = 
    (from t in _table
     where t.Id == id
           && t.Time >= startTime
           && t.Time <= endTime
     let secondsSince2000 = (int)(t.Time- baseTime).TotalSeconds
     group t by secondsSince2000 - (secondsSince2000 % timeSlotInSeconds)
     into g
     orderby g.Key 
     select g.Average(a => a.Value))).ToList();

查询会慢得多。

答案 1 :(得分:0)

看看我刚才写的这个例子。这听起来像你要做的,但我不确定它是用SQL还是.NET进行分组。

http://mikeinmadison.wordpress.com/2008/03/12/datetimeround/

答案 2 :(得分:0)

也许你可以这样做:

var wattList = (from t in _table
                where t.Id == id
                   && t.Time >= startTime
                   && t.Time <= endTime
               ).GroupBy(x => (int) ((x.Time - startTime).TotalSeconds / intervalInSeconds))
                .Select(grp => grp.Average(x => x.Value));