我有 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 查询中这样做,而不必自己用循环解析表?
我有 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 查询中这样做,而不必自己用循环解析表?
您可以在 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)
. (因为您可以在时间上进行快速最近的搜索)。
这是执行此操作的一种方法:
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
这种方法在每个t3时间之前和之后查找最近的t1和t2时间/值,然后计算出要在语句中使用哪一个之前/之后的行。select
这种方式的优点是 SQL Server 可以有效地使用索引来获取之前/之后的值;为计算每个t3时间使用哪个之前/之后值所做的工作应该通过有效检索之前/之后值来抵消。