我有诸如的数据,

ID  time
1   9/6/2016 00:01:00
1   9/6/2016 00:01:30
1   9/6/2016 00:02:00
1   9/6/2016 00:04:30
1   9/6/2016 00:05:30
1   9/6/2016 01:05:30
1   9/6/2016 05:05:30
1   9/6/2016 05:06:30
2   9/6/2016 01:55:00
2   9/6/2016 01:56:29
2   9/6/2016 01:57:31
2   9/6/2016 03:55:00
2   9/6/2016 04:13:00
2   9/6/2016 04:15:21

对于每个ID,我想将一个称为flag的新变量设置为1并检查时间的第一个值。从时间的第一个值开始,我要检查距第一个条目3分钟以内的条目,并将所有内容设置为1。一旦时间条目超过3分钟,我想将flag变量设置为2,然后再次设置请在该时间后的3分钟内检查输入内容,然后继续对每个ID进行操作。我想为每个ID找到3分钟的分组,以便为​​每个ID形成表格。

我想要的输出是
ID  time              flag
1   9/6/2016 00:01:00   1
1   9/6/2016 00:01:30   1
1   9/6/2016 00:02:00   1
1   9/6/2016 00:04:30   2
1   9/6/2016 00:05:30   2
1   9/6/2016 01:05:30   2
1   9/6/2016 05:05:30   2
1   9/6/2016 05:06:30   2
2   9/6/2016 01:55:00   1
2   9/6/2016 01:56:29   1
2   9/6/2016 01:57:31   1
2   9/6/2016 03:55:00   2
2   9/6/2016 04:13:00   3
2   9/6/2016 04:15:21   3

对于ID 1,标志设置为1,并一直检查3分钟条目,直到第3行为止;一旦它超过3分钟,它就设置为2,并再次开始检查3分钟条目。同样对于ID 2。

以下是我尝试过的
select ID, time, rank() over (order by time) as rank from table_name;

这是整个表的排名。我在想,我们可以为每个ID排序,然后调用第一个值,然后用剩余值减去它,然后在此处编写子查询。

有没有更好的有效方法来做到这一点?我在这里使用Hive查询。任何帮助,将不胜感激。

最佳答案

请注意,您的样本输出不正确;对于ID = 1,时间= 01:05:30是00:05:30之后的整整一个小时,但是两者的标记相同。

这是专门使用Oracle SQL的解决方案。检查“标志转换”条件;按照我写的方式,只有在经过严格超过3分钟后,才会​​启动新标记。如果要在刚过3分钟后开始新计数,请将第一个不等式更改为non-strict,将第二个不等式更改为严格。

解决方案*使用递归分解子查询,因此需要Oracle 11.2或更高版本。

*注意:从逻辑上讲,我不必在其中减去3 /(24 * 60);相反,不等式应该与3 /(24 * 60)进行比较。这在Oracle 12中有效,但使用ORA-00600导致Oracle 11.2上的数据库崩溃,有人告诉我这是Oracle在11.2(在12.1中已修复)的递归查询实现中的一个已知错误的标记。我是非付费客户,所以我自己无法访问错误信息。我测试了下面在Oracle 11.2上发布的查询,该查询可以运行,而简化版本崩溃了。两种版本在12.1上都能正常工作。

with
     inputs ( id, time ) as (
       select 1, to_date('9/6/2016 00:01:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 00:01:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 00:02:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 00:04:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 00:05:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 01:05:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 05:05:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 1, to_date('9/6/2016 05:06:30', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 01:55:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 01:56:29', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 01:57:31', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 03:55:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 04:13:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
       select 2, to_date('9/6/2016 04:15:21', 'mm/dd/yyyy hh24:mi:ss') from dual
     ),
     rec ( id, time, flag, time_diff ) as (
       select  id, time, 1,
               time - min(time) over (partition by id order by time) - 3/(24*60)
         from  inputs
       union all
       select  id, time, flag + 1,
               time - min(time) over (partition by id order by time) - 3/(24*60)
         from  rec
         where time_diff > 0
     )
select   id, time, flag
from     rec
where    time_diff <= 0
order by id, time
;

输出:
  ID TIME                      FLAG
---- ------------------- ----------
   1 06/09/2016 00:01:00          1
   1 06/09/2016 00:01:30          1
   1 06/09/2016 00:02:00          1
   1 06/09/2016 00:04:30          2
   1 06/09/2016 00:05:30          2
   1 06/09/2016 01:05:30          3
   1 06/09/2016 05:05:30          4
   1 06/09/2016 05:06:30          4
   2 06/09/2016 01:55:00          1
   2 06/09/2016 01:56:29          1
   2 06/09/2016 01:57:31          1
   2 06/09/2016 03:55:00          2
   2 06/09/2016 04:13:00          3
   2 06/09/2016 04:15:21          3

 14 rows selected

09-11 11:57