Oracle选择查找几种状态的发生

时间:2018-12-27 19:02:10

标签: sql oracle select gaps-and-islands

我有以下数据:

STATUS                      DATE                        TIME                        
B                           20181011                    13:28:27                    
B                           20181011                    13:36:05                    
B                           20181011                    15:28:40                    
I                           20181011                    15:28:57                    
I                           20181011                    15:41:56                    
I                           20181018                    08:21:43                    
B                           20181018                    13:38:00                    
I                           20181019                    17:03:00                    
B                           20181023                    09:45:54                    
I                           20181023                    10:35:44                    
I                           20181023                    10:38:11                    

每次我都有一个状态“ B”的序列时,我都必须使用最后一个,对状态“ I”使用相同的序列,这样我就可以考虑上述规则来获得每一个这种状态,并计算它们之间的时间。我尝试了一些选择但没有成功,也找不到像我这样的问题。

编辑: 我希望选择可以使结果如下:

STATUS                      DATE                        TIME                        
B                           20181011                    15:28:40                    
I                           20181018                    08:21:43                    
B                           20181018                    13:38:00                    
I                           20181019                    17:03:00                    
B                           20181023                    09:45:54                    
I                           20181023                    10:38:11                    

3 个答案:

答案 0 :(得分:0)

这是一个选项,它通过CTE引导您前进,以便您可以跟踪发生的情况。我建议您一一执行。

此外,我希望实际上有一个DATE数据类型列;否则,如果有两个(日期和时间),则将它们存储在VARCHAR2列中(可能),这是个坏主意-我建议您更改模型并使用一个{{1 }}数据类型列。

我们在这里:

DATE
  • SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss'; Session altered. SQL> with test (status, datum) as 2 (select 'B', to_date('11.10.2018 13:28:27', 'dd.mm.yyyy hh24:mi:ss') from dual union all 3 select 'B', to_date('11.10.2018 13:36:05', 'dd.mm.yyyy hh24:mi:ss') from dual union all 4 select 'B', to_date('11.10.2018 15:28:40', 'dd.mm.yyyy hh24:mi:ss') from dual union all 5 select 'I', to_date('11.10.2018 15:28:57', 'dd.mm.yyyy hh24:mi:ss') from dual union all 6 select 'I', to_date('11.10.2018 15:41:56', 'dd.mm.yyyy hh24:mi:ss') from dual union all 7 select 'I', to_date('18.10.2018 08:21:43', 'dd.mm.yyyy hh24:mi:ss') from dual union all 8 select 'B', to_date('18.10.2018 13:38:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all 9 select 'I', to_date('19.10.2018 17:03:00', 'dd.mm.yyyy hh24:mi:ss') from dual union all 10 select 'B', to_date('23.10.2018 09:45:54', 'dd.mm.yyyy hh24:mi:ss') from dual union all 11 select 'I', to_date('23.10.2018 10:35:44', 'dd.mm.yyyy hh24:mi:ss') from dual union all 12 select 'I', to_date('23.10.2018 10:38:11', 'dd.mm.yyyy hh24:mi:ss') from dual 13 ), 14 inter as 15 (select status, lag(status) over (order by datum) lag_status, datum 16 from test 17 ), 18 inter_2 as 19 (select status, datum, 20 sum(case when status = nvl(lag_status, status) then 0 else 1 end) over (order by datum) grp 21 from inter 22 ) 23 select status, max(datum) datum 24 from inter_2 25 group by status, grp 26 order by datum; S DATUM - ------------------- B 11.10.2018 15:28:40 I 18.10.2018 08:21:43 B 18.10.2018 13:38:00 I 19.10.2018 17:03:00 B 23.10.2018 09:45:54 I 23.10.2018 10:38:11 6 rows selected. SQL> CTE从上一行中选择INTER
  • STATUS根据上一行和当前行的INTER_2列值相同还是不同来创建组
  • 最终查询按STATUSSTATUS(组)对数据进行分组,并选择GRP MAX

答案 1 :(得分:0)

首先获取与条件匹配的所有日期时间对,然后加入主表:

select tablename.* from (
  select mydate, mytime from tablename t
  where not exists (
    select 1 from tablename 
    where 
      tablename.status = t.status 
      and 
      concat(tablename.mydate, tablename.mytime) = (
        select min(concat(tablename.mydate, tablename.mytime)) from tablename where concat(mydate, mytime) > concat(t.mydate, t.mytime)
      )
  )
) d
inner join tablename
on d.mydate = tablename.mydate and d.mytime = tablename.mytime;

请参见this other answer

答案 2 :(得分:0)

这是空白和岛屿问题的一个版本。对于此版本,我认为lead()是最好的方法:

select status, date, time
from (select t.*,
             lead(status) over (order by date, time) as next_status
      from t
     ) t
where next_status is null or next_status <> status;