Here's one way of doing this:
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.
This approach find the most recent t1 and t2 times/values both before and after each t3 times, then works out which one of the before/after rows to use in the select
statement.
The advantage with this way is that SQL Server can uses indexes effectively to get the before/after values; the work done to work out which before/after value to use for each t3 time should be offset by efficient retrieval of the before/after values.