Oracle select 查找几个状态的出现
Oracle select to find occurences of couple of status
我有以下数据:
状态日期时间
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' 相同,这样我就可以根据上面的规则得到每对这个状态并计算他们之间的时间。我尝试了一些 selects 但没有成功,我也找不到任何像我这样的问题。
编辑:
我希望 select 可以得到以下结果:
状态日期时间
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
这是一个选项,它通过 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 从前一行中选择 STATUS
值
INTER_2
根据前一行和当前行的 STATUS
列值相同还是不同 创建组
- 最终查询按
STATUS
和 GRP
(组)分组数据并选择 MAX
DATUM
值
首先获取所有符合条件的日期时间对并加入主table:
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
这是空岛问题的一个版本。对于这个版本,我认为 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;
我有以下数据:
状态日期时间 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' 相同,这样我就可以根据上面的规则得到每对这个状态并计算他们之间的时间。我尝试了一些 selects 但没有成功,我也找不到任何像我这样的问题。
编辑: 我希望 select 可以得到以下结果:
状态日期时间 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
这是一个选项,它通过 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 从前一行中选择STATUS
值INTER_2
根据前一行和当前行的STATUS
列值相同还是不同 创建组
- 最终查询按
STATUS
和GRP
(组)分组数据并选择MAX
DATUM
值
首先获取所有符合条件的日期时间对并加入主table:
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
这是空岛问题的一个版本。对于这个版本,我认为 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;