2

我有 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 查询中这样做,而不必自己用循环解析表?

4

2 回答 2

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). (因为您可以在时间上进行快速最近的搜索)。

于 2013-06-15T17:06:50.917 回答
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 与演示

这种方法在每个t3时间之前和之后查找最近的t1t2时间/值,然后计算出要在语句中使用哪一个之前/之后的行。select

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

于 2013-06-15T17:39:19.287 回答