Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 查找连续值长度小于阈值的记录_Sql_Postgresql_Group By_Window Functions_Gaps And Islands - Fatal编程技术网

Sql 查找连续值长度小于阈值的记录

Sql 查找连续值长度小于阈值的记录,sql,postgresql,group-by,window-functions,gaps-and-islands,Sql,Postgresql,Group By,Window Functions,Gaps And Islands,这是桌子 timestamp | tracker_id | position -------------------------------+------------+---------- 2020-02-01 16:23:45.571429+00 | 15 | 1 2020-02-01 16:23:45.857143+00 | 11 | 1 2020-02-01 16:23:46.42

这是桌子

           timestamp           | tracker_id | position 
-------------------------------+------------+----------
 2020-02-01 16:23:45.571429+00 | 15         |        1
 2020-02-01 16:23:45.857143+00 | 11         |        1
 2020-02-01 16:23:46.428571+00 | 15         |        1
 2020-02-01 16:23:46.714286+00 | 11         |        2
 2020-02-01 16:23:54.714288+00 | 15         |        2
 2020-02-01 16:23:55+00        | 15         |        1
 2020-02-01 16:23:55.285714+00 | 11         |        1
 2020-02-01 16:23:55.571429+00 | 15         |        1
 2020-02-01 16:23:55.857143+00 | 15         |        1
 2020-02-01 16:23:56.428571+00 | 11         |        1
 2020-02-01 16:23:56.714286+00 | 15         |        1
 2020-02-01 16:23:57+00        | 11         |        2
 2020-02-01 16:23:58.142857+00 | 11         |        2
 2020-02-01 16:23:58.428571+00 | 15         |        1
 2020-02-01 16:23:58.714286+00 | 11         |        2
 2020-02-01 16:23:59+00        | 11         |        1
 2020-02-01 16:23:59.285714+00 | 15         |        1
 2020-02-01 16:23:59.295714+00 | 10         |        1
 2020-02-01 16:23:59.305714+00 | 10         |        2
 2020-02-01 16:23:59.385714+00 | 10         |        2
 2020-02-01 16:23:59.485714+00 | 10         |        3
阈值=3

这里,跟踪器id的位置从1->1->2->1->1->1->2->2->1更改为15

跟踪器id的位置:11从1->2->1->1->2->2->1更改

跟踪器id的位置:从1->2->2->3更改为10

追踪器编号:15
1之间连续2的最大长度这是一个间隙和孤岛问题

首先,可以使用行号之间的差异构建相邻记录的组。然后,您可以聚合每个组,并使用滞后和超前恢复周围组的位置。最后一步是应用过滤逻辑

select tracker_id
from (
    select
        tracker_id,
        position,
        count(*) cnt,
        lag(position) over(partition by tracker_id order by max(timestamp)) lag_position,
        lead(position) over(partition by tracker_id order by max(timestamp)) lead_position
    from (
        select
            t.*,
            row_number() over(partition by tracker_id order by timestamp) rn1,
            row_number() over(partition by tracker_id, position order by timestamp) rn2
        from mytable t
    ) t
    group by tracker_id, position, rn1 - rn2
) t
where
    position = 2
    and lag_position = 1
    and lead_position = 1
group by tracker_id
having max(cnt) < 3
这与您的示例数据一起产生:

| tracker_id | | ---------: | | 15 |
没有必要把这当作一个缺口和孤岛问题来处理。只需使用窗口功能:

select tracker_id
from (select t.*,
             min(position) over (partition by tracker_id
                                 order by timestamp
                                 rows between 2 preceding and current row
                                ) as min_pos_3,
             max(position) over (partition by tracker_id
                                 order by timestamp
                                 rows between 2 preceding and current row
                                ) as max_pos_3
      from t
     ) t
group by tracker_id
having count(*) filter (where min_pos_3 = max_pos_3) = 0

这只是查看每个跟踪器超过三个3的最小值和最大值。它只返回值总是不同的行。

我对您的输入表进行了一些修改,添加了tracker\u id=9进行测试

窗口函数可以解决此问题,如:行数、lead

select x.* 
into #temp1
from
(
    select ' 2020-02-01 16:23:45.571429+00 ' as time_stamp, 9 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:45.857143+00 ' as time_stamp, 9 as tracker_id, 3 as position UNION ALL 
    select ' 2020-02-01 16:23:46.428571+00 ' as time_stamp, 9 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:24:45.571429+00 ' as time_stamp, 9 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:25:45.857143+00 ' as time_stamp, 9 as tracker_id, 2 as position UNION ALL
    select ' 2020-02-01 16:26:45.857143+00 ' as time_stamp, 9 as tracker_id, 3 as position UNION ALL
    select ' 2020-02-01 16:27:45.857143+00 ' as time_stamp, 9 as tracker_id, 3 as position UNION ALL
    select ' 2020-02-01 16:28:46.428571+00 ' as time_stamp, 9 as tracker_id, 1 as position UNION ALL
    select ' 2020-02-01 16:23:45.571429+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:45.857143+00 ' as time_stamp, 11 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:46.428571+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:46.714286+00 ' as time_stamp, 11 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:54.714288+00 ' as time_stamp, 15 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:55+00        ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:55.285714+00 ' as time_stamp, 11 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:55.571429+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:55.857143+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:56.428571+00 ' as time_stamp, 11 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:56.714286+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:57+00        ' as time_stamp, 11 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:58.142857+00 ' as time_stamp, 11 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:58.428571+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:58.714286+00 ' as time_stamp, 11 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:59+00        ' as time_stamp, 11 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:59.285714+00 ' as time_stamp, 15 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:59.295714+00 ' as time_stamp, 10 as tracker_id, 1 as position UNION ALL 
    select ' 2020-02-01 16:23:59.305714+00 ' as time_stamp, 10 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:59.385714+00 ' as time_stamp, 10 as tracker_id, 2 as position UNION ALL 
    select ' 2020-02-01 16:23:59.485714+00 ' as time_stamp, 10 as tracker_id, 3 as position) x
;

select 
    *,
    ROW_NUMBER() OVER(PARTITION BY tracker_id ORDER BY time_stamp) tracker_id_rownumber,
    case when position=1 then 1 else 0 end is_pos0_equals_1, --is current row position=1?
    case when (LEAD(position, 1) OVER (PARTITION BY tracker_id ORDER BY time_stamp))=2 then 1 else 0 end is_pos1_equals_2, --is next row position=2?
    case when (LEAD(position, 2) OVER (PARTITION BY tracker_id ORDER BY time_stamp))=2 then 1 else 0 end is_pos2_equals_2, --next next row..
    case when (LEAD(position, 3) OVER (PARTITION BY tracker_id ORDER BY time_stamp))=2 then 1 else 0 end is_pos3_equals_2  --next next next row..
into #temp2
from #temp1
;

--leave only trackers with intervals of type {1, ... ,1}
select a.tracker_id, a.tracker_id_rownumber interval_start, min(b.tracker_id_rownumber) interval_end
into #temp3
from #temp2 a
inner join #temp2 b on (a.tracker_id=b.tracker_id and a.tracker_id_rownumber<b.tracker_id_rownumber)
where a.position=1 and b.position=1
group by a.tracker_id, a.tracker_id_rownumber

--check each 3-elements subset (are there any triples of consecutive '2'?) and mark triples of consecutive '2'
select a.*,b.tracker_id tracker_id_,
    case when b.interval_end - b.interval_start>=4 then
        case when (a.is_pos1_equals_2=1 and a.is_pos2_equals_2=1 and a.is_pos3_equals_2=1) then 0 else 1 end
    else
        1
    end 'is_less_than_threshold'
into #temp4
from #temp2 a 
inner join #temp3 b on a.tracker_id=b.tracker_id and a.tracker_id_rownumber between b.interval_start and b.interval_end-1

--output trackers
select a.tracker_id, min(a.is_less_than_threshold) is_ok
from #temp4 a
group by a.tracker_id
having min(a.is_less_than_threshold)=1
输出

跟踪器id正常吗

9 | 1


15 | 1

此查询查找位置长度小于阈值的记录。但是,我需要找到位置长度从未超过阈值的记录。例如,在上面的示例中,不应考虑tracker_id:11,因为位置的长度超过了时间戳2020-02-01 16:23:56.714286+00后的阈值,仍然考虑tracker_id:11。@saintlyzero:我在我的答案中添加了一个db fiddle供您参考。此查询仅显示tracker 15。这是完整的查询吗?因为我有一些语法错误。@saintlyzero:current\u行必须是当前行row@GMB . . . 谢谢。谢谢你的解释!