Reputation: 8302
I've got two tables, simplified as seen below.
CREATE TABLE value(
Timestamp DATETIME2,
Value float NOT NULL,
PRIMARY KEY(Timestamp)
);
CREATE TABLE location(
Timestamp DATETIME2,
Position GEOMETRY NOT NULL,
PRIMARY KEY(Timestamp)
);
Performing a simple LEFT JOIN such as:
SELECT V.Timestamp, V.Value, L.Position
FROM value V
LEFT JOIN location L ON V.Timestamp = L.Timestamp;
This yields all the values but there are NULL's present where there isn't an exact match on Timestamp
.
My goal is to get an interpolated position for every value in the value table. I need to somehow interpolate values in my query and this is where I'm getting stuck.
EDIT: I've since discovered I can add a CASE statement to check for NULL
SELECT
V.Timestamp,
V.Value,
CASE WHEN L.Position IS NULL THEN
(<something clever here>)
ELSE
L.Position
END As Position
FROM value V
LEFT JOIN location L ON V.Timestamp = L.Timestamp;
Upvotes: 4
Views: 1374
Reputation: 9292
Have you looked at the Spatial Tools library? link
They have a interpolation function that looks to be what you need:
SqlGeometry InterpolateBetweenGeom(SqlGeometry start, SqlGeometry end, double distance)
I amended my first example to now calculate the midpoint of the two closest points, but I think the above library is a much better option. To use my function, you pass in the timestamps for those NULL postions and function returns the midpoint as a geom position.
This might be of use for someone in a similar situation:
if object_id('dbo.fn_CalcMidPointByTime') is not null
drop function dbo.fn_CalcMidPointByTime;
go
create function [dbo].[fn_CalcMidPointByTime] (@baseTimestamp datetime2)
returns geometry
as
begin
declare @return geometry,
@fromPoint geometry,
@toPoint geometry;
declare @stage table (i tinyint, position geometry);
-- stage the high / low points
insert into @stage (i, position)
select row_number() over(order by d.[Timestamp] asc), position.ToString()
from ( select top(2) [Timestamp]
from dbo.Location
order by abs(datediff(ms, [Timestamp], @baseTimestamp)) asc
) as d([Timestamp])
join dbo.Location l on
d.[Timestamp] = l.[Timestamp];
select @fromPoint = position from @stage where i = 1;
select @toPoint = position from @stage where i = 2;
-- create linestring from the two points
declare @ls geometry = geometry::Parse(@fromPoint.STUnion(@toPoint).ToString()).STConvexHull().ToString();
-- draw a rectangle around the two points, and choose the center
select @return = @ls.STEnvelope().STCentroid();
return @return;
end
go
Upvotes: 3
Reputation: 16677
I think you should change your query to return 3 sets of values on every row:
these should be the largest time and position that is less than the current one,
the current time and position,
and the smallest time and position greater then the current one.
in this way, each row will have enough info to do the math...
Upvotes: 1