表中最接近的时间戳

时间:2013-06-15 16:48:47

标签: sql sql-server

我有3张桌子。

Table 1 has 2 fields : Time/Value

Table 2 has 2 fields : Time/Value

Table 3 has 1 field : Time

我想为表3中的每个时间找到表1和表2中最接近时间字段的值。

表1和表2中的时间精度约为毫秒。表3中的时间精度为1秒。

是否可以在SQL查询中执行此操作而无需自己用循环解析表?

2 个答案:

答案 0 :(得分:4)

您可以在SQL中执行此操作,但由于SQL可用的工具速度很慢,因此对于Table3的每一行,您必须查找Table1和Table2的所有行。如果您使用更通用的语言手动编写解决方案,则可以针对问题域进行优化。如果您只是作为临时请求执行它,SQL将是最容易编码的,看起来像这样:

SELECT t3.time,
  (SELECT TOP 1 t1.value
   FROM t1
   ORDER BY ABS(DATEDIFF(ms,t3.time,t1.time)) ASC
  ) as t1value,
  (SELECT TOP 1 t2.value
   FROM t2
   ORDER BY ABS(DATEDIFF(ms,t3.time,t2.time)) ASC
  ) as t2value
FROM t3

如何运作

对于t3中的每一行,按时间差对t1和t2进行选择,只取最小值。

关于速度的说明

此代码将在O(N3 * N1) + O(N3 * N2)中运行。如果您手动编码好的算法,您将能够获得O(N3 * log(N1)) + O(N3 * log(N2)。 (因为你可以在当时进行快速最近的搜索)。

答案 1 :(得分:0)

这是实现此目的的一种方式:

select t3.Time
  , t1Time = case when abs(datediff(ms, t1Below.Time, t3.Time))
      <= abs(datediff(ms, t1Above.Time, t3.Time))
    then t1Below.Time
    else t1Above.Time
    end
  , t1Value = case when abs(datediff(ms, t1Below.Time, t3.Time))
      <= abs(datediff(ms, t1Above.Time, t3.Time))
    then t1Below.Value
    else t1Above.Value
    end
  , t2Time = case when abs(datediff(ms, t2Below.Time, t3.Time))
      <= abs(datediff(ms, t2Above.Time, t3.Time))
    then t2Below.Time
    else t2Above.Time
    end
  , t2Value = case when abs(datediff(ms, t2Below.Time, t3.Time))
      <= abs(datediff(ms, t2Above.Time, t3.Time))
    then t2Below.Value
    else t2Above.Value
    end
from t3
  outer apply (select top 1 t1Below.*
              from t1 t1Below
              where t3.Time >= t1Below.Time
              order by t1Below.Time desc) t1Below
  outer apply (select top 1 t1Above.*
              from t1 t1Above
              where t3.Time <= t1Above.Time
              order by t1Above.Time) t1Above
  outer apply (select top 1 t2Below.*
              from t2 t2Below
              where t3.Time >= t2Below.Time
              order by t2Below.Time desc) t2Below
  outer apply (select top 1 t2Above.*
              from t1 t2Above
              where t3.Time <= t2Above.Time
              order by t2Above.Time) t2Above

SQL Fiddle with demo

此方法在每个 t3 次之前和之后找到最新的 t1 t2 次/值,然后计算出哪一个要在select语句中使用的前/后行。

这种方式的优点是SQL Server可以有效地使用索引来获取前/后值;为解决每个 t3 时间使用的值之前/之后所做的工作应该通过有效检索前/后值来抵消。