从时间序列数据中获取超过阈值的时间量

时间:2014-09-18 13:22:28

标签: mysql sql

给出一个这样的表:

`sensor` int(11)
`reading` decimal(5,2)
`timestamp` datetime

表示温度数据并在值发生变化时记录条目,我将如何查找记录在给定值之上的时间量?

所以可能会有一堆读数,例如16到30,这个要求是找到超过16的时间。

1 个答案:

答案 0 :(得分:0)

两个解决方案

我提出两个解决方案:

  • 一个查询,但由于子查询,我不知道它是否对大量数据非常有效;
  • 一个功能。

<强>模式

我用这个表测试了查询和函数:

CREATE TABLE `temperature` (
    `sensor` int(11) NOT NULL,
    `timestamp` datetime NOT NULL,
    `reading` decimal(5, 2) NOT NULL,
    PRIMARY KEY (`sensor`,`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

还有一些数据:

1;2014-09-18 17:00:00;15.0
1;2014-09-18 18:00:00;16.0
1;2014-09-18 19:00:00;15.0

解决方案1:查询

SELECT SUM(elapsed_time)
FROM (
    SELECT
        (UNIX_TIMESTAMP((
            SELECT MIN(t2.timestamp)
            FROM temperature t2
            WHERE t1.sensor = t2.sensor AND t1.timestamp < t2.timestamp
        )) - UNIX_TIMESTAMP(t1.timestamp))
        AS elapsed_time
    FROM temperature t1
    WHERE t1.sensor = 1 AND t1.reading >= 16.0
) a;

解决方案2:功能

该函数返回传感器的值以秒为单位的时间量。

它将时间量初始化为0.然后读取所需传感器的所有读数。如果温度高于您的要求,它会增加下一次读数之前的时间。最后,它返回高于传感器要求的时间量。

DROP FUNCTION IF EXISTS getTotalTimeAbove;
DELIMITER $$
CREATE FUNCTION getTotalTimeAbove(sensor_id INTEGER, above DECIMAL(5, 2))
    RETURNS INTEGER
BEGIN
    DECLARE sum INTEGER DEFAULT 0;
    DECLARE curr_time DATETIME;
    DECLARE next_time DATETIME;
    DECLARE curr_reading INTEGER;
    DECLARE next_reading INTEGER;
    DECLARE done INT DEFAULT FALSE;
    DECLARE cur CURSOR FOR
        SELECT `timestamp`, `reading`
        FROM `temperature`
        WHERE `sensor` = sensor_id;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO next_time, next_reading;
        IF done THEN
            LEAVE read_loop;
        END IF;
        IF (curr_reading >= above) THEN
            SET sum = sum + (UNIX_TIMESTAMP(next_time) - UNIX_TIMESTAMP(curr_time));
        END IF;
        SET curr_time = next_time;
        SET curr_reading = next_reading;
    END LOOP;
    CLOSE cur;
    RETURN sum;
END
$$
DELIMITER ;

查询及其结果:

> SELECT getTotalTimeAbove(1, 16.0);
3600

<强>加成

您可以使用此查询获得传感器的总记录时间:

SELECT UNIX_TIMESTAMP(MAX(`timestamp`)) - UNIX_TIMESTAMP(MIN(`timestamp`))
FROM `temperature`
WHERE `sensor` = 1