【数据分析】sql实现数据固定时间间隔去重!!!

简介:
前一段时间遇到一个需求问题,关于固定时间间隔对数据去重,例如要统计一个区域内某个人的出现频率,但是在一段时间内(15s)多次出现又会影响数据分析的准确性,所以为了提高统计数据的准确性,所以有效的出现次数时间间隔大于15s,如下图:
在这里插入图片描述
由上图可知,此人在0s、5s、8s、16s、25s、35s处出现过,我们以0s处出现为起始点,以15s为间隔时间计算,满足条件的出现次数为:0s、16s和35s处出现的点,而5s、8s、25s出现的点我们认为是重复数据,可丢弃;

实现分析:
在程序中能够实现这个数据筛选的方式还是比较多得,比如队列+哈希表就可以实现,但是在程序中实现首先把数据加载到内存中,在数据量比较大的情况下会比较占用内存,同时也要消耗数据从数据库加载到内存的性能,所以比较高效的实现方式是在数据库中实现数据的筛选去重(注:我们占不考虑数据库的性能损耗,和业务场景有关系),在数据库中通过sql的方式实现业务逻辑就比较复杂,本人也是思考了一段时间,主要考虑点有两个:1)功能实现;2)sql的执行性能,尤其是第二点,一个比较耗费性能的sql实现等于没有实现;

通过sql实现固定时间间隔去重的功能,主要依赖于数据库中的两个函数:递归函数动态窗口函数

实现思路:
1)首先按照人员进行分组,对每组数据进行升序排序,并设置序号;
在这里插入图片描述

   在不同分组中,每条数据被赋予序号,按照排序信息递增,s1、s2、s3...sn;

2)以升序数据序列第一条数据为起始点,固定时间15s为窗口大小,找到窗口内距离窗口起始数据最远的数据wLast1,组成一条数据;依次类推,计算每条数据作为起始点是,满足窗口大小数据中的距离最远的数据;
在这里插入图片描述

3)从起始点开始计算间隔时间大于15s的数据,第一条数据为起始点数据,第二条数据为wLast1数据的序号+1,第三条数据为第二条数据的wLastn数据的序号+1,通过递归函数依次计算,得到筛选后的数据;方便理解,请看下图:
在这里插入图片描述

   在查询s1的下一条数据时,下一条数据肯定是w1窗口之外的第一条数据s3,而s3等于窗口内的最后一条数据s2+1;

样例数据库表:

CREATE TABLE IF NOT EXISTS `person_appear_record` (
  `id` int(6) unsigned NOT NULL,
  `face_id` varchar(32) unsigned NOT NULL,
  `appear_time` bingint unsigned NOT NULL
  PRIMARY KEY (`id`)
) 

业务实现sql:

WITH RECURSIVE person_temp_01 AS (
  SELECT
    person_id,
    appear_time
    ROW_NUMBER () OVER ( PARTITION BY person_id ORDER BY appear_time ASC ) row_id,
    LAST_VALUE ( appear_time ) OVER ( PARTITION BY person_id ORDER BY appear_time ASC RANGE BETWEEN 0 PRECEDING AND 15000 FOLLOWING ) lastValue 
  FROM
    person_appear_record
  ),
  person_temp_02 AS (
  SELECT
    t01.person_id,
    t01.appear_time,
    t01.row_id,
    t01.lastValue,
    t02.person_id person_id2,
    t02.appear_time appear_time2,
    t02.row_id row_id2,
    t02.lastValue lastValue2 
  FROM
    person_temp_01 t01,
    person_temp_01 t02 
  WHERE
    1=1
    AND t01.person_id = t02.person_id 
    AND t01.row_id + 1 = t02.row_id 
  ),
  person_temp_03 AS (
  SELECT
    f01.person_id,
    f01.appear_time,
    f01.lastValue,
    f01.row_id 
  FROM
    person_temp_02 f01 
  WHERE
    f01.row_id = 1 UNION
  SELECT
    t21.person_id2 person_id,
    t21.appear_time2 appear_time,
    t21.lastValue2 lastValue,
    t21.row_id2 row_id 
  FROM
    person_temp_02 t21,
    person_temp_03 t50 
  WHERE
    1=1
    AND t21.person_id = t50.person_id 
    AND t21.appear_time = t50.lastValue 
  ) 
SELECT
  *,
  TO_CHAR( TO_TIMESTAMP( appear_time / 1000 ), 'yyyy-mm-dd HH24:MI:SS' ) 
FROM
  person_temp_03 
WHERE
  1 = 1 
  AND person_id = 33 
ORDER BY
  person_id,
  appear_time ASC

注:本人使用的是postgresql数据库

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylan~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值