Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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从定义了偏差的每个集合中获取n个结果_Sql_Oracle_Oracle11g - Fatal编程技术网

SQL从定义了偏差的每个集合中获取n个结果

SQL从定义了偏差的每个集合中获取n个结果,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,使用Oracle 11g并具有如下表: USER | TIME ----- | -------- User1 | 08:15:50 User1 | 10:42:22 User1 | 10:42:24 User1 | 10:42:35 User1 | 10:50:01 User2 | 13:23:05 User2 | 13:23:34 User2 | 13:24:01 User2 | 13:24:02 对于每个用户,如果可用,我需要获得3条记录,第一次和最后一次之间的偏差不到一分钟。如果行数超

使用Oracle 11g并具有如下表:

USER  | TIME
----- | --------
User1 | 08:15:50
User1 | 10:42:22
User1 | 10:42:24
User1 | 10:42:35
User1 | 10:50:01
User2 | 13:23:05
User2 | 13:23:34
User2 | 13:24:01
User2 | 13:24:02
对于每个用户,如果可用,我需要获得3条记录,第一次和最后一次之间的偏差不到一分钟。如果行数超过3,则它们将不符合条件。你能给我一些线索吗

结果应该如下所示:

User1 | 10:42:22
User1 | 10:42:24
User1 | 10:42:35

这是我的想法。我没有实时Oracle,SQLFiddle无法工作,因此请告知结果:

CREATE TABLE t (
  u VARCHAR(5),
  t DATETIME
);

INSERT INTO t
  (u, t)
VALUES
  ('User1', '2001-01-01 08:15:50'),
  ('User1', '2001-01-01 10:42:22'),
  ('User1', '2001-01-01 10:42:24'),
  ('User1', '2001-01-01 10:42:35'),
  ('User1', '2001-01-01 10:50:01'),
  ('User2', '2001-01-01 13:23:05'),
  ('User2', '2001-01-01 13:23:34'),
  ('User2', '2001-01-01 13:24:01'),
  ('User2', '2001-01-01 13:24:02');

SELECT
    z.u,
    min(z.t) evt_start,
    max(z.t) evt_end
FROM
(
    SELECT y.*, SUM(prev_or_2prev_not_within) OVER(PARTITION BY u ORDER BY t ROWS UNBOUNDED PRECEDING) as ctr
    FROM
    (
       SELECT 
           t.*, 
           CASE WHEN 
               t - LAG(t) OVER(PARTITION BY u ORDER BY t) < 1.0/1440.0 OR
               t - LAG(t, 2) OVER(PARTITION BY u ORDER BY t) < 1.0/1440.0
               THEN 0 ELSE 1
           END as prev_or_2prev_not_within
        FROM
           t
    ) y
 ) z
GROUP BY
    z.u,
    z.ctr
HAVING COUNT(*) = 3
我相信它将建立一个递增计数器,当前一行或前一行在当前行的一分钟内时,该计数器不会递增。它通过将行分类为0或1来实现这一点,当出现0时,“对所有前面的行求和”操作将生成一个不变的计数器。然后在该计数器上分组,正好出现3次。分区使计数器对每个用户有效

你可以在这里看到它的作用:

如前所述,这是SQL Server,我没有oracle,但SQL Server使用的术语和oracle的逻辑应该大致相似-oracle支持滞后、无界和等,并且它使用dateA-dateB->一个代表一天全部或部分的浮点数和每天1440分钟进行日期计算,1/1440应代表一分钟的浮动。sqlserver使用的数据类型可能与oracle略有不同,此查询取决于我称之为t的时间-不喜欢保留字/关键字的列名列是日期时间,而不是看起来像时间的字符串。如果数据是字符串,请对其进行排序,使其不使用内部子查询生成日期时间,或者更改数据存储,使其存储为日期时间类型

你说你想要一个告诉用户和事件时间的结果——最简单的方法是使用min和max来给出日期范围。如果您非常希望显示所有3行,则可以将此查询的输出连接回evt_start和evt_end之间的表,或者使用某种字符串聚合类型函数,为您提供最外层组操作的时间列表

我将使用带范围子句的分析计数:

结果:

USER_ TIME_
----- --------
User1 10:42:22
User1 10:42:24
User1 10:42:35
编辑:
正如@CaiusJard所注意到的,当间隔为10:52:01、10:53:00、10:53:59时,第一个答案可能会显示不正确的值。有一些方法可以纠正这一点。首先是找到小组中的最小和最大时间,并检查条件numtodserval max-min,“day”对不起,这里有点新。我正在使用添加到描述中的oracle 11g。如果给定用户在一分钟内拥有多组3条记录,会发生什么情况?在这种情况下会发生什么?当一分钟内有4条记录时会发生什么?你想要a,b,c还是b,c,d或两者都要?所有的组都必须列出,即使它不止一个。如果我们有10:42:30和10:43:25和10:44:20会怎么样?时间超过1分钟,但间隔不到1分钟。谢谢。工作起来很有魅力。巧妙的技巧,我不知道Oracle可以根据当前行值设置范围。我想这会有几个bug。。请参见-根据Angel的规则,此结果集中不应有任何行。考虑把整个事情在一个组中通过计数=3?谢谢。你是对的。我修改了答案并在两个样本数据集上进行了测试,您的数据集没有返回,正如预期的那样,还有一个稍大一些。谢谢我需要一些时间来运行它,因为oracle和mssql之间的数据类型不同,正如您上面提到的,实际上需要一些时间来了解其背后的全部想法:但这是一个非常有趣和迅速的决定。如果答案有用,请使用^箭头进行投票。您可以对任意数量的答案执行此操作,但绿色勾号只能用于一个答案
USER_ TIME_
----- --------
User1 10:42:22
User1 10:42:24
User1 10:42:35
with t as (
  select row_number() over (order by user_, time_) rn, tbl.*,
         count(1) over (partition by user_ order by time_ 
                        range between interval '1' minute preceding 
                                  and interval '1' minute following) cnt
    from (select user_, to_date(time_, 'hh24:mi:ss') time_ from tbl) tbl),
r as (select rn, 
             case when 3 = lag(cnt) over (partition by user_ order by time_) 
                   and 3 = cnt 
                   and 3 = lead(cnt) over (partition by user_ order by time_) 
                  then 1 
             end flag
        from t )
select * from t 
  join (select rn-1 r1, rn r2, rn+1 r3 from r where flag = 1) r
    on rn in (r1, r2, r3)