【问题标题】:MySQL: Calculate intermediate value at a given timestamp (Linear interpolation)MySQL:计算给定时间戳的中间值(线性插值)
【发布时间】:2015-02-22 21:43:15
【问题描述】:

给定下表,我想在 00:00:00 处选择每个 ID 的值。当在这个确切时间有一个条目时,返回它,否则使用线性插值(00:00:00 之前和之后的最接近值之间的假想图形线)计算它。如果在给定时间之后还没有值,则返回最后一个值,或使用最后两点的线性插值。

ID|Timestamp|Value
1|2015-01-01 23:00:00|90
1|2015-01-02 01:00:00|110
2|2015-01-01 23:00:00|210
2|2015-01-02 01:00:00|190
3|2015-01-02 00:00:00|50
4|2015-01-01 23:00:00|100
5|2015-01-01 22:00:00|80
5|2015-01-01 23:00:00|90

结果:

ID|Value
1|100
2|200
3|50
4|100
5|100

这是否仅适用于 MySQL 以及如何实现?

【问题讨论】:

  • 在 MySQL 中是可能的。在支持窗口函数的数据库中会容易得多(几乎可以是任何其他数据库)。
  • @Mihai:不,5 将在 22:30:00 时为 85。在 00:00:00,它将是 90 (23:00:00) +10 = 100。

标签: mysql


【解决方案1】:

首先,让我们将其拆分为像 #3 这样的单条目与双条目(其余部分):

( SELECT ID, value FROM tbl GROUP BY ID HAVING COUNT(*) = 1 )
UNION ALL
( ... ) -- This needs interpolation code, below
ORDER BY ID;

将这对行分开是很棘手的,因为没有很好的方法来做“groupwise-max”。因此,相反,我将使用 @variables 并按顺序遍历表格。

四舍五入到最近的午夜可能是 ROUND(... / 86400) * 86400 。潜在的问题是您所在的 time_zone。我不想解决这个问题。

SELECT ID, val FROM (
SELECT  ID,
        IF(ID != @prevID, '1st', '2nd') AS picker,  -- See WHERE filter, below
        @ts = timestamp,   -- Need an INT here, not sure that is what I have
        @dts = @ts - @prev_ts,
        @dval = value - @prev_val,
        @midnight := ROUND(@ts / 86400) * 86400,  -- DST issues?
        value + (@midnight - @ts) * (@dval / @dts) AS val, -- interpolate
        @prev_id = ID,
        @prev_ts = @ts,
        @prev_val = value
    FROM ( SELECT @prevID := 0 ) AS Initialize
    JOIN tbl
    ORDER BY ID, timestamp
) AS x
WHERE picker = '2nd'
ORDER BY ID

把那个怪物作为UNION的第二部分。

【讨论】:

  • 感谢这个美丽的“怪物”!
猜你喜欢
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 2017-03-19
  • 1970-01-01
相关资源
最近更新 更多