相关文章推荐
博学的枇杷  ·  SQL中的嵌套CASE语句 - ·  3 周前    · 
唠叨的硬盘  ·  如何实现MySQL case when ...·  3 周前    · 
微笑的青蛙  ·  selenium ...·  2 周前    · 
帅呆的篮球  ·  子查詢 (SQL Server) - ...·  2 周前    · 
近视的花卷  ·  阿勒泰地区生态保护与修复工作推进不力 ...·  4 月前    · 
不要命的汉堡包  ·  亚洲最大的红叶观赏区就藏在中国,分分钟让你知 ...·  1 年前    · 
体贴的风衣  ·  凌小东郑怡云在哪一章 - 抖音·  2 年前    · 
坏坏的凳子  ·  寻找章莹颖的“一千零一夜”,多么希望这只是故 ...·  2 年前    · 
低调的斑马  ·  海猫络合物 - 萌娘百科 万物皆可萌的百科全书·  2 年前    · 
Code  ›  sql - 请教一个数据查询问题(连续一段时间大于某个值),希望大家能够提供方法 -
date select
https://segmentfault.com/q/1010000008459119
直爽的毛衣
2 年前
segmentfault segmentfault
注册登录
问答 博客 标签 活动
发现
✓ 使用“Bing”搜本站 使用“Google”搜本站 使用“百度”搜本站 站内搜索
注册登录
  1. 首页
  2. 问答
  3. sql
  4. 问答详情

请教一个数据查询问题(连续一段时间大于某个值),希望大家能够提供方法

头像
qnsh
27 1 6 13
发布于
2017-02-23
更新于
2017-03-01

数据表中有时间和数据值两列,
现在需要查询连续大于等于3分钟大于某个值(从大于某个值开始一直到小于该值结束)的数据,
并计算出连续时间,和该段时间的平均值。如何通过SQL语句实现该要求。
数据示例

排序 sql oracle
阅读 12.5k
2 个回答
得票 最新
头像
邢爱明
5k 6 21 35
发布于
2017-02-24
更新于
2017-02-24
✓ 已被采纳

简单做了个测试,希望对你有帮助。

创建表和测试数据

CREATE TABLE t_log(f_time DATE, f_value NUMBER);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 12:00:00', 'dd-mm-yyyy hh24:mi:ss'), 100);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 12:00:01', 'dd-mm-yyyy hh24:mi:ss'), 101);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 12:00:02', 'dd-mm-yyyy hh24:mi:ss'), 102);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 12:00:03', 'dd-mm-yyyy hh24:mi:ss'), 103);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 12:00:04', 'dd-mm-yyyy hh24:mi:ss'), 95);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 13:00:00', 'dd-mm-yyyy hh24:mi:ss'), 108);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 13:01:00', 'dd-mm-yyyy hh24:mi:ss'), 105);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 13:03:00', 'dd-mm-yyyy hh24:mi:ss'), 99);
insert into T_LOG (F_TIME, F_VALUE)
values (to_date('24-02-2017 13:05:00', 'dd-mm-yyyy hh24:mi:ss'), 108);

查询语句,假设时间字段没有重复值结果才会正确:
大概分三个步骤:

  • 先按照时间字段排序,计算出每个连续大于等于目标值分组的第一行记录(判断标准是当前行大于等于目标值,同时下一行小于目标值,下面sql语句t表内容)

  • 计算上面分组的日期范围计算出来(下面sql语句中t2的内容),并过滤连续时间超过3分钟,形成表t3

  • 然后将数据表和t3表关联,就可以得到连续大于目标值的行分组。

  • WITH t2 AS (
      SELECT f_group1, LEAD(f_group1, 1, to_date('9999-12-31', 'yyyy-mm-dd')) OVER (ORDER BY f_time) AS f_group2
      FROM (
        SELECT f_time, f_value, CASE WHEN f_value >= 100 AND LAG(f_value, 1, 0) OVER(ORDER BY f_time) < 100 THEN f_time ELSE NULL END AS f_group1
        FROM t_log
        ORDER BY f_time
      WHERE f_group1 IS NOT NULL
    ), t3 as (
      select * from t2 where (f_group2 - f_group1) > = 180
    SELECT 
      t3.f_group1,
      (MAX(t_log.f_time) - MIN(t_log.f_time))*86400, AVG(t_log.f_value)
    FROM t_log INNER JOIN t3 ON t_log.f_time >= t3.f_group1 AND t_log.f_time < t3.f_group2
    WHERE f_value >= 100
    GROUP BY t3.f_group1
    头像
    萝卜
    2.3k 1 4 22
    发布于
    2017-02-27
    更新于
    2017-02-28

    用阿里巴巴今年以来的股价 t_log 做例子,求连续4天以上股价大于$102的区间。

    f_time f_val 2017-02-01 07:16:17 101.57 2017-02-02 16:36:38 100.84 2017-02-03 04:47:59 100.39 2017-02-06 13:12:05 100.90 2017-02-07 06:32:45 100.83 2017-02-08 02:27:47 103.57 2017-02-09 07:40:26 103.34 2017-02-10 17:59:55 102.36 2017-02-13 14:40:22 103.10 2017-02-14 17:14:21 101.59 2017-02-15 05:33:37 101.55 2017-02-16 03:04:19 100.82 2017-02-17 09:44:34 100.52 2017-02-21 18:26:33 102.12 2017-02-22 01:14:24 104.20 2017-02-23 03:40:00 102.46 2017-02-24 15:38:03 102.95

    Postgresql代码:

    flip_time as ( select * from ( select case when (lag(f_val, 1, 0.0) over win < 102 and f_val >= 102) or (f_val >= 102 and lead(f_val, 1, 0.0) over win < 102) then f_time else null end as f_time from t_log window win as (order by f_time)) as foo where f_time is not null), duration as ( select t1, t2 from ( select f_time as t1, lead(f_time) over (order by f_time) as t2, row_number() over () as num from flip_time) as foo where t2 - t1 >= interval '4 days' and num%2=1) select d.t1 t_start, d.t2 t_end, d.t2 - d.t1 as duration, round(avg(g.f_val),4) mean from t_log g inner join duration d on d.t1 <= g.f_time and g.f_time <= d.t2 group by d.t1, d.t2, d.t2 - d.t1;
  • flip_time :阈值(102)区间段开始或结束的时点。通过窗口函数 lag() 和 lead() 比较前后两行是否跨越阈值取得。

  • duration : flip_time 中一定是“开始-结束”的循环,利用此特性进一步加工出把开始和结束时点放在同一行,且长度符合要求(4天)的行。

  • duration 和 t_log 联接可计算出持续时间和平均值。

  • 运行结果是:

    t_start t_end duration 2017-02-08 02:27:47
     
    推荐文章
    博学的枇杷  ·  SQL中的嵌套CASE语句 -
    3 周前
    唠叨的硬盘  ·  如何实现MySQL case when 套用子查询的具体操作步骤_mob649e81540090的技术博客_
    3 周前
    微笑的青蛙  ·  selenium 难定位元素,时间插件,下拉框定位,string - konglingbin
    2 周前
    帅呆的篮球  ·  子查詢 (SQL Server) - SQL Server | Microsoft Learn
    2 周前
    近视的花卷  ·  阿勒泰地区生态保护与修复工作推进不力 侵占破坏林草问题突出_典型案例_新疆维吾尔自治区生态环境厅
    4 月前
    不要命的汉堡包  ·  亚洲最大的红叶观赏区就藏在中国,分分钟让你知道什么是“树树皆秋色”
    1 年前
    体贴的风衣  ·  凌小东郑怡云在哪一章 - 抖音
    2 年前
    坏坏的凳子  ·  寻找章莹颖的“一千零一夜”,多么希望这只是故事,女孩还好好的 - 哔哩哔哩
    2 年前
    低调的斑马  ·  海猫络合物 - 萌娘百科 万物皆可萌的百科全书
    2 年前
    今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
    删除内容请联系邮箱 2879853325@qq.com
    Code - 代码工具平台
    © 2024 ~ 沪ICP备11025650号