我有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查询中执行此操作而无需自己用循环解析表?
答案 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
此方法在每个 t3 次之前和之后找到最新的 t1 和 t2 次/值,然后计算出哪一个要在select
语句中使用的前/后行。
这种方式的优点是SQL Server可以有效地使用索引来获取前/后值;为解决每个 t3 时间使用的值之前/之后所做的工作应该通过有效检索前/后值来抵消。