【问题标题】:Finding Ranges where condition is met查找满足条件的范围
【发布时间】:2019-01-22 19:59:24
【问题描述】:

我有一个 mysql 表,其中包含来自传感器的浮点值和读取时间的日期时间戳。读数以 1 分钟的间隔存储(有些可能会丢失)。

我正在尝试设计一个查询,该查询将为我提供一个事件列表(浮点值大于某个阈值的连续范围),其中包括该范围内超过阈值的第一条记录的时间戳,以及结束时间戳,值回落到阈值以下。

ID      Value   Timestamp
2172846 1.0 2018-06-29 17:28:00
2172853 1.1 2018-06-29 17:29:00
2172860 1.1 2018-06-29 17:31:00
2172867 1.3 2018-06-29 17:32:00
2172874 1.3 2018-06-29 17:33:00
2172881 1.5 2018-06-29 17:34:00
2172888 1.4 2018-06-29 17:35:00
2172895 1.3 2018-06-29 17:36:00
2172902 1.2 2018-06-29 17:37:00
2172909 1.1 2018-06-29 17:38:00
2172916 1.0 2018-06-29 17:39:00
2172923 1.0 2018-06-29 17:40:00
2172930 1.0 2018-06-29 17:41:00
2172937 1.0 2018-06-29 17:42:00
2172944 1.0 2018-06-29 17:43:00
2172951 1.7 2018-06-29 17:44:00
2172958 2.0 2018-06-29 17:45:00
2172965 1.8 2018-06-29 17:46:00
2172972 1.3 2018-06-29 17:47:00
2172979 1.0 2018-06-29 17:48:00
2172986 1.0 2018-06-29 17:49:00
2172993 1.0 2018-06-29 17:50:00
2173000 1.0 2018-06-29 17:51:00
2173007 1.0 2018-06-29 17:52:00
2173014 1.0 2018-06-29 17:53:00

我已经进行了一些初步研究,但还没有走得更远。

阈值大于 1 的样本数据集的预期输出将是这样的。

start_timestamp      end_timestamp
2018-06-29 17:29:00  2018-06-29 17:39:00
2018-06-29 17:44:00  2018-06-29 17:48:00

【问题讨论】:

  • 你能告诉我们你尝试了什么吗?
  • 我不知道从哪里开始,这就是问题所在。
  • 如果有多个连续范围怎么办?
  • 会有多个连续的范围,我想找到每个出现的地方。
  • ID 总是增加 7 吗?

标签: mysql sql time-series


【解决方案1】:

如果你的mysql支持window function

,这是一个gaps-and-islands问题

你可以试试这个查询。

SELECT MIN(`Timestamp`)start_timestamp,MAX(`Timestamp`)end_timestamp
FROM (
  select *,MIN(`Timestamp`) over(order by `Timestamp`) mindt,
   ROW_NUMBER() over(order by `Timestamp`) rn
  from T
  where value > 1.0
)t1
group by (TIMESTAMPDIFF(MINUTE,mindt,`Timestamp`)+1  - rn)

sqlfiddle

【讨论】:

  • 同样,递增的分钟数与此问题无关
【解决方案2】:

在 MySQL 中,您将使用变量:

select min(timestamp), max(timestamp)
from (select t.*,
             (@grp := if(value > 1.0, @grp, @grp + 1)) as grp
      from (select t.* from t order by timestamp) t cross join
           (select @grp := 0) params
     ) t
where value > 1.0
group by grp;

【讨论】:

  • 我们将订单放在两个不同的级别上是否重要?
  • @Strawberry 。 . .是的。但更重要的区别是您在一个表达式中分配 @prev 并在另一个表达式中使用它。 MySQL 不保证 SELECT 中表达式的求值顺序。
  • @Strawberry 。 . .谢谢。
【解决方案3】:

这是一个想法。它返回的范围与您的范围非常微妙,但也许您可以弄清楚如何调整它...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id SERIAL PRIMARY KEY 
,value DECIMAL(3,1)
,dt DATETIME
);

INSERT INTO my_table VALUES
(2846, 1.0, '2018-06-29 17:28:00'),
(2853, 1.1, '2018-06-29 17:29:00'),
(2860, 1.1, '2018-06-29 17:31:00'),
(2867, 1.3, '2018-06-29 17:32:00'),
(2874, 1.3, '2018-06-29 17:33:00'),
(2881, 1.5, '2018-06-29 17:34:00'),
(2888, 1.4, '2018-06-29 17:35:00'),
(2895, 1.3, '2018-06-29 17:36:00'),
(2902, 1.2, '2018-06-29 17:37:00'),
(2909, 1.1, '2018-06-29 17:38:00'),
(2916, 1.0, '2018-06-29 17:39:00'),
(2923, 1.0, '2018-06-29 17:40:00'),
(2930, 1.0, '2018-06-29 17:41:00'),
(2937, 1.0, '2018-06-29 17:42:00'),
(2944, 1.0, '2018-06-29 17:43:00'),
(2951, 1.7, '2018-06-29 17:44:00'),
(2958, 2.0, '2018-06-29 17:45:00'),
(2965, 1.8, '2018-06-29 17:46:00'),
(2972, 1.3, '2018-06-29 17:47:00'),
(2979, 1.0, '2018-06-29 17:48:00'),
(2986, 1.0, '2018-06-29 17:49:00'),
(2993, 1.0, '2018-06-29 17:50:00'),
(3000, 1.0, '2018-06-29 17:51:00'),
(3007, 1.0, '2018-06-29 17:52:00'),
(3014, 1.0, '2018-06-29 17:53:00');

SELECT MIN(dt) dt_start
     , MAX(dt) dt_end 
  FROM 
     ( SELECT x.*
            , CASE WHEN @prev=(value<=1) THEN @i:=@i ELSE @i:=@i+1 END i
            , @prev:=value<=1 prev 
         FROM my_table x
            , (SELECT @prev:=null, @i:=0) vars 
        ORDER 
           BY id
     ) x 
 WHERE prev=0 
 GROUP   
    BY i;
+---------------------+---------------------+
| dt_start            | dt_end              |
+---------------------+---------------------+
| 2018-06-29 17:29:00 | 2018-06-29 17:38:00 |
| 2018-06-29 17:44:00 | 2018-06-29 17:47:00 |
+---------------------+---------------------+

【讨论】:

    猜你喜欢
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2013-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多