使用SQL查找零值之间的局部最大值

时间:2015-10-29 20:52:30

标签: mysql sql

我有一张表来自IOT设备的每分钟数据。每分钟都有一个新行,其中包含时间戳和表示度量标准的值。度量标准从0开始,并在重置和重新开始之前递增一段时间。

当我绘制它时,它看起来像图片。我想找到每次运行的局部最大值,如蓝色圆圈所示。

是否可以查找和分组度量标准所在的连续行? 0然后找到每组的最大值?

enter image description here

更新

表格结构:

+-------------+------------------+
| Field       | Type             |
+-------------+------------------+
| id          | int(10) unsigned |
| timestamp   | timestamp        |
| metric_name | varchar(32)      |
| value       | int(10)          |
+-------------+------------------+

5 个答案:

答案 0 :(得分:1)

这是基于以下假设:

  1. Id是一个完美的顺序整数(没有间隙)
  2. 您希望在0值
  3. 之前直接记录值

    代码:

    SELECT *
      FROM metrics m1
     WHERE m.id IN (    
       SELECT m2.id - 1
         FROM metrics m2
        WHERE m1.value = 0)
    

答案 1 :(得分:0)

我在一个时间戳为零之前加入了所有不为零的东西,然后我发现在0和最后一个之间没有值的那些......

SELECT  
    value,
    timestamp 
FROM
    metrics 
    LEFT JOIN metrics zeros
        on metrics.time < zeros.time
        and zeros.value = 0
    LEFT JOIN metrics betweenZero
        on metrics.time < betweenZero.time
        and betweenZero.time < zeros.time
    INNER JOIN metrics  noBetweens
        on table.id = noBetweens.id
        and betweenZero.id IS NULL

如果您需要最终的metric_nameWHERE metric_name = the_metric_name,那么

答案 2 :(得分:0)

这应该给你每组的最大值以及每个窗口的开始时间和结束时间,只有1次通过数据。

select metric_name, max(value) value, max(start_group) start_time, max(end_group) end_time from(
select metric_name, value,
       case when @prev_ts is not null then @prev_ts end prev_ts,
       case when value = 0 then @ts := timestamp end as start_group,
       @ts as grouping,
       @prev_ts := timestamp end_group
from metric join (select @prev_ts := null as p) prev
order by timestamp
) q
group by metric_name, grouping;

这将创建一个1000行的样本数据集,每分钟重置一次。

insert into metric(timestamp, metric_name, value)
select now() - interval rn second, 'pressure', v
from(
    select @rn := @rn + 1 rn, mod(1000 - @rn,60) * pow(1000 - mod(@rn,121),1) v
    from   table_with_at_least_1000_rows
    join (select @rn := 0) rn
    limit 1000
) q
;

答案 3 :(得分:0)

我的解决方案并不关心差距,但我假设id s的序列是单调的,即它们随着时间的推移逐渐增加。 (您甚至可以在查询中用id代替timestamp。)我做了一些次要的语法类型错误,自从我第一次尝试以来我已经纠正过,并且我用一个简单的小提琴测试了它。我认为它有效。

select t0.*
from
    T t0 inner join
    (
        select max_z, max(id) as max_id, max(value) as local_max
        from
            (
            select
                id, value,
                (
                select max(t2.id) as max_id from T t2
                where t2.id < t.id and t2.value = 0
                ) as max_z
            from T t
            where t.value <> 0
            ) p /* partitions */
        group by p.max_z
    ) x /* extrema */
        on t0.id between max_z and max_id and t0.value = x.local_max

顺便说一下,当本地最大值达到平局时,它会返回所有行。

http://sqlfiddle.com/#!9/de832/2

答案 4 :(得分:0)

试试这个:

SELECT 
        T.min_id
        ,T.max_id
        ,MAX(M.value) as local_max
    FROM
        metrics M
        JOIN (
            SELECT
                    id as min_id
                    ,(
                        SELECT MIN(id) FROM Metrics MI
                            WHERE
                                MI.id > MO.id
                                AND MI.value = 0) as max_id

                FROM Metrics MO
                WHERE
                    value = 0
        )T ON M.id BETWEEN T.min_id AND T.max_id
    GROUP BY
        T.min_id, T.max_id