创建空间插值函数

时间:2016-07-09 20:12:17

标签: sql oracle

我有一个包含数据的大表

(ID, LATITUDE, LONGITUDE, SPEED, TIME)

其中时间包含每隔几秒后ID's位置(LAT, LON)的信息。

例如:

在08:42:05 PM,08:42:15 PM,08:42:18 PM等。

我想应用线性插值算法来查找数据库中不存在的ID位置(例如:在08:42:07 PM)。

在SQL或PL / SQL中是否有一个优雅的方法来创建这些插值函数?

是否有其他有效的空间插值方法可用于更有效的结果?

修改:点击表格的here(预期结果标记为粗体,并且可能因使用的插值函数而异。)

1 个答案:

答案 0 :(得分:0)

这是一个解决方案,适用于严格大于表中最短时间且小于或等于表中最长时间的任何时间(对于给定的id)。

:id和:time是绑定变量。在SQL Developer或Toad中,您将看到一个弹出窗口,询问您绑定变量的值。对于:id你可以输入1和for:你输入类似2016-04-30 23:15:33的时间(没有单引号 - 输入被自动解释为字符串);代码适用于on_number():id和to_date()around:time,使用正确的日期格式模型。

对于我的样本数据(在顶部的位置表中),唯一有效的:id是1,并注意我以相反的顺序输入了时间(以模拟行是无序的这一事实);测试时,时间必须大于SECOND行中的时间且小于或等于第一行中的时间。

第一个技巧是在表中插入一行输入时间(:time),对于lat和lon使用NULL。其余的是相当标准的SQL,使用分析函数lag()和lead()以及插值公式。

with positions (id, lat, lon, time) as (
       select 1, 30.200, 39.294, to_date('2016-04-30 23:20:56', 'yyyy-mm-dd hh24:mi:ss') 
           from dual union all
       select 1, 29.390, 39.407, to_date('2016-04-30 23:04:42', 'yyyy-mm-dd hh24:mi:ss') 
           from dual
     ),
     augmented (id, lat, lon, time, idx) as (
       select  id, lat , lon , time, 1 from positions union all
       select to_number(:id), null, null, to_date(:time, 'yyyy-mm-dd hh24:mi:ss'), 0 
           from dual
     ),
     before_and_after as (
       select lat, lon, time, idx,
              lag(lat)   over (partition by id order by time, idx) as prev_lat,
              lag(lon)   over (partition by id order by time, idx) as prev_lon,
              lag(time)  over (partition by id order by time, idx) as prev_time,
              lead(lat)  over (partition by id order by time, idx) as next_lat,
              lead(lon)  over (partition by id order by time, idx) as next_lon,
              lead(time) over (partition by id order by time, idx) as next_time
       from   augmented
       where  id = to_number(:id)
     ) select * from before_and_after;
select prev_lat + (next_lat - prev_lat) * 
            (to_date(:time, 'yyyy-mm-dd hh24:mi:ss') - prev_time) / 
                (next_time - prev_time) as interp_lat,
       prev_lon + (next_lon - prev_lon) * 
            (to_date(:time, 'yyyy-mm-dd hh24:mi:ss') - prev_time) / 
                (next_time - prev_time) as interp_lon
from   before_and_after
where  idx = 0;