在数据表中查找最接近给定时间的时间戳的行

时间:2015-12-02 23:19:34

标签: c#

我有一个名为Timestamp和其他列的数据表。我正在尝试找到时间戳最接近给定时间的那些行。例如,有些行具有不同的时间戳。如何查找最接近12/02/2015 15:00:00,12 / 02/2015 15:15:00等的行。在以下示例中,时间戳为12/02/2015 14:59的行:48.089和12/02/2015 15:16:01.376是给定时间内最关闭的行12/02/2015 15:00:00和12/02/2015 15:15:00。

...

12/02/2015 14:57:59.768

12/02/2015 14:59:48.089

12/02/2015 15:00:59.453

12/02/2015 15:02:12.145

12/02/2015 15:10:3​​5.789

12/02/2015 15:16:01.376

.......

我尝试使用

DataRow[] drRows = dtMyRecords.Select("MIN(Timestamp-#12/02/2015 15:00:00#)"); 

object obj = dtStationRecords.Compute("MIN(Timestamp-'12/02/2015 15:15:00')", null);
找到它。但它们不起作用。你能给出解决方案吗?

3 个答案:

答案 0 :(得分:1)

从广义上讲,您希望获得增量时间的绝对值(虽然不要尝试克里斯的代码,但您不能在TimeSpan上调用Math.Abs​​())。您可能必须首先解析输入,例如使用DateTime.Parse()。

这里有一些代码可以选择最接近的代码。它使用模拟数据(dates),因为我不知道您的DataSet是什么样的。

string[] dates = new[] { "12/02/2015 14:57:59.768", "12/02/2015 14:59:48.089" };
DateTime target = DateTime.Parse("12/02/2015 14:58:00");
var closest = dates
   .Select(date => new {
      date, distance = Math.Abs(DateTime.Parse(date)Ticks - target.Ticks)})
   .OrderBy(dt => dt.distance)
   .First().date;

结果:

12/02/2015 14:57:59.768

但是,为什么不让数据库为您执行此操作呢?除非您重复使用数据,否则这将导致更小的事务和更快的查找。

DECLARE @target DateTime = '2015-05-05 12:15:00' --your query input
SELECT TOP 1 Timestamp 
FROM YourTable 
ORDER BY ABS( DATEDIFF( SS, Timestamp, @target ) ) 
-- "SS" above means second-level precision.

答案 1 :(得分:0)

您希望从目标时间中获取数据库中时间戳的绝对差值,并采用最小差异。

var result = data.Min(r = Math.Abs(r.Timestamp - targettime));

答案 2 :(得分:0)

我怀疑你正在寻找这样的东西:

DateTime target = new DateTime(2015,12,2,15,0,0);

var closest = dtMyRecords.AsEnumerable()
    .Select(drRow => drRow.Field<DateTime>("Timestamp"))
    .OrderBy(d => Math.Abs(d.Ticks - target.Ticks))
    .First();

如果这不是一个性能关键的应用程序,这将正常工作,但使用.OrderBy()的麻烦是你真的不需要重新排序元素。您需要枚举一次DataTable并记录最近的项目。

以下算法有点丑陋,但计算效率更高:

DateTime target = new DateTime(2015,12,2,15,0,0);

DateTime closest=DateTime.MinValue;
long closestTicks=long.MaxValue;

foreach(var d in dtMyRecords.AsEnumerable().Select(drRow=>drRow.Field<DateTime>("Timestamp")))
{
    long currentTicks = Math.Abs(d.Ticks - target.Ticks);
    if(currentTicks >= closestTicks) continue;
    closestTicks = currentTicks;
    closest = d;
}

// "closest" will now hold the closest date (or defaults if the sequence contains no elements)

使用LINQ的.Aggregate()方法可以实现类似的东西(以及IMO,同样丑陋)。遗憾的是,LINQ并没有为您提供干净,高效,开箱即用的方式来满足您的需求,但是,如果您有兴趣,可以查看一个库,MoreLINQ,提供MinBy()扩展方法。即使您选择不使用它,source code也可以通知您决定使用的算法。