Oracle 选择查找出现的几个状态

Posted

技术标签:

【中文标题】Oracle 选择查找出现的几个状态【英文标题】:Oracle select to find occurences of couple of status 【发布时间】:2018-12-27 19:02:10 【问题描述】:

我有以下数据:

状态日期时间 B 20181011 13:28:27 B 20181011 13:36:05 B 20181011 15:28:40 我 20181011 15:28:57 我 20181011 15:41:56 我 20181018 08:21:43 B 20181018 13:38:00 我 20181019 17:03:00 B 20181023 09:45:54 我 20181023 10:35:44 我 20181023 10:38:11

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

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

状态日期时间 B 20181011 15:28:40 我 20181018 08:21:43 B 20181018 13:38:00 我 20181019 17:03:00 B 20181023 09:45:54 我 20181023 10:38:11

【问题讨论】:

我想如果您根据该示例数据发布所需的结果会有所帮助。 我用预期的结果编辑了问题。 这是一个典型的“差距和孤岛”问题。搜索 ***。该解决方案已多次记录在案。 【参考方案1】:

这里有一个选项,通过 CTE 引导您跟踪正在发生的事情。我建议你一个一个执行。

另外,我希望实际上有一个 DATE 数据类型列;否则,如果其中有两个(日期和时间),您将它们存储到 VARCHAR2 列(可能)这是一个坏主意 - 我建议您更改模型并使用一个 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>
INTER CTE 从上一行中选择STATUSINTER_2 根据前一行和当前行的 STATUS 列值是否相同或不同来创建组 最终查询按STATUSGRP(组)对数据进行分组,并选择MAX DATUM

【讨论】:

感谢您的解决方案。我测试了所有解决方案,您的解决方案最适合我的需求。【参考方案2】:

首先获取所有符合条件的日期时间对并加入主表:

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;

见demo

【讨论】:

【参考方案3】:

这是间隙和孤岛问题的一个版本。对于这个版本,我认为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;

【讨论】:

以上是关于Oracle 选择查找出现的几个状态的主要内容,如果未能解决你的问题,请参考以下文章

关于数组的几个小题目-冒泡排序二分查找直接选择排序反转数组

常见的几个算法

ETL工具kettle的几个小插件(字符串替换,字段选择,将字段值设置为常量)

jquery选择器查找子元素

Oracle 8i 从具有相同 ID 但不同状态的多行数据集中选择查询

如何将一行中的几个<div>实现类似单选框试的点击选择,实现如下图的效果