首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于相邻记录插值时间戳的SQL查询

基于相邻记录插值时间戳的SQL查询
EN

Stack Overflow用户
提问于 2017-08-13 20:14:34
回答 4查看 508关注 0票数 2

我使用Oracle并有下表:

代码语言:javascript
运行
复制
create table test as
select to_date('02.05.2017 00:00', 'DD.MM.YYYY HH24:MI') as DT, 203.4 as VAL from dual union all
select to_date('02.05.2017 01:00', 'DD.MM.YYYY HH24:MI') as DT, 206.7 as VAL from dual union all
select to_date('02.05.2017 02:00', 'DD.MM.YYYY HH24:MI') as DT, 208.9 as VAL from dual union all
select to_date('02.05.2017 03:00', 'DD.MM.YYYY HH24:MI') as DT, 211.8 as VAL from dual union all
select to_date('02.05.2017 04:45', 'DD.MM.YYYY HH24:MI') as DT, 212.3 as VAL from dual union all
select to_date('02.05.2017 06:15', 'DD.MM.YYYY HH24:MI') as DT, 214.5 as VAL from dual union all
select to_date('02.05.2017 08:12', 'DD.MM.YYYY HH24:MI') as DT, 215 as VAL from dual
;


DT                   VAL
----------------------------
02.05.2017 00:00     203.4
02.05.2017 01:00     206.7
02.05.2017 02:00     208.9
02.05.2017 03:00     211.8
02.05.2017 04:45     212.3
02.05.2017 06:15     214.5
02.05.2017 08:12     215 

我需要编写SQL查询(或PL/SQL过程),以便为任何时间戳(DT)插入值(VAL),假设该值在表中的两个相邻记录之间不断增加(即。线性插值)。

示例:

  • 当我为时间戳“02.05.2017 00:00”选择值时,查询应该给我203.4 (表中有这样的时间戳记录)
  • 当我为时间戳“02.05.2017 00:30”选择值时,查询应该给我205.05 (表中不存在这样的时间戳记录,所以我们在203.4到206.7之间取“中间”,因为想要的时间戳在它们的时间戳之间处于中间)
  • 当我为时间戳“02.05.2017 00:15”选择值时,查询应该给我204.225 ( 203.4到206.7之间的“第四部分”)

解决这类任务的最简单方法是什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-08-14 06:06:30

我认为这个更紧凑,它避免了自我连接:

代码语言:javascript
运行
复制
WITH t AS 
    (SELECT DT, VAL, 
        LEAD(DT, 1, DT) OVER (ORDER BY DT) AS FOLLOWING_DT,
        LEAD(VAL, 1, VAL) OVER (ORDER BY VAL) AS FOLLOWING_VAL
    FROM TEST)
SELECT VAL + (FOLLOWING_VAL - VAL) * ( (:timestamp - DT) / (FOLLOWING_DT - DT) )
FROM t
WHERE :timestamp BETWEEN DT AND FOLLOWING_DT;
票数 3
EN

Stack Overflow用户

发布于 2017-08-13 20:59:43

我认为实现这一目标的最简单方法是使用PL/SQL函数,如下所示:

代码语言:javascript
运行
复制
create or replace function get_val(dt in date) return number
is
  cursor exact_cursor(dt in date) is
    select t.val from t where t.dt = exact_cursor.dt;
  cursor earlier_cursor(dt in date) is
    select t.dt, t.val from t where t.dt < earlier_cursor.dt
    order by t.dt desc;
  cursor later_cursor(dt in date) is
    select t.dt, t.val from t where t.dt > later_cursor.dt
    order by t.dt asc;

  result      number;
  factor      number;
  earlier_rec earlier_cursor%rowtype;
  later_rec   later_cursor%rowtype;
begin
  open exact_cursor(dt);
  fetch exact_cursor into result;
  close exact_cursor;
  if result is not null then
    return result;
  end if;

  -- No exact match. Perform linear interpolation between values
  -- from earlier and later records.
  open earlier_cursor(dt);
  fetch earlier_cursor into earlier_rec;
  close earlier_cursor;

  open later_cursor(dt);
  fetch later_cursor into later_rec;
  close later_cursor;

  -- Return NULL unless earlier and later records found
  if earlier_rec.dt is null or later_rec.dt is null then
    return null;
  end if;

  factor := (dt - earlier_rec.dt) / (later_rec.dt - earlier_rec.dt);
  result := earlier_rec.val + factor * (later_rec.val - earlier_rec.val);
  return result;
end;
/
票数 0
EN

Stack Overflow用户

发布于 2017-08-13 21:43:52

你不需要游标。你需要找到两个最近的记录,一个在上面,一个在下面,然后取它们的平均值。就像这样:

代码语言:javascript
运行
复制
select :timestamp,
       (case when lower.val = upper.val then val
             else lower.val + (upper.val - lower.val) * ( (:timestamp - lower.dt) / (upper.dt - lower.dt) )
        end) as imputed_val
from (select *
      from (select dt, val
            from t
            where dt <= :timestamp
            order by dt desc
           )
      where rownum = 1
     ) lower cross join
     (select *
      from (select dt, val
            from t
            where dt >= :timestamp
            order by dt asc
           )
      where rownum = 1
     ) upper;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45664532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档