我想将表的ACTIVE值设置如下:
FLAG=E
=> ACTIVE=1
,并且对于任何后续的FLAG
值,直到FLAG=H
FLAG=H
=> ACTIVE=0
,并且对于任何后续的FLAG
值,直到FLAG=E
以此类推。
示例
ID | FLAG | ACTIVE
---+------+-------
1 | E | 1
2 | V | 1
3 | H | 0
4 | V | 0
5 | E | 1
6 | S | 1
7 | V | 1
8 | D | 1
9 | H | 0
该值按日期排序。 为简单起见,我添加了一个ID列以获取列顺序。
问题
什么是SQL更新语句?
注意:
业务规则也可以表示为:
如果对于给定的行,前E
的计数-前H
的计数为1,则该行的ACTIVE为1,否则为0。
答案 0 :(得分:1)
您可以使用the last_value()
analytic function获得active
的值:
select id, flag,
last_value(case when flag = 'E' then 1 when flag = 'H' then 0 end) ignore nulls
over (order by id) as active
from your_table;
作为演示:
create table your_table (id, flag) as
select 1, 'E' from dual
union all select 2, 'V' from dual
union all select 3, 'H' from dual
union all select 4, 'V' from dual
union all select 5, 'E' from dual
union all select 6, 'S' from dual
union all select 7, 'V' from dual
union all select 8, 'D' from dual
union all select 9, 'H' from dual;
select id, flag,
last_value(case when flag = 'E' then 1 when flag = 'H' then 0 end) ignore nulls
over (order by id) as active
from your_table;
ID F ACTIVE
---------- - ----------
1 E 1
2 V 1
3 H 0
4 V 0
5 E 1
6 S 1
7 V 1
8 D 1
9 H 0
您可以使用相同的内容进行更新,尽管合并可能会更简单:
alter table your_table add active number;
merge into your_table
using (
select id,
last_value(case when flag = 'E' then 1 when flag = 'H' then 0 end) ignore nulls
over (order by id) as active
from your_table
) tmp
on (your_table.id = tmp.id)
when matched then update set active = tmp.active;
9 rows merged.
select * from your_table;
ID F ACTIVE
---------- - ----------
1 E 1
2 V 1
3 H 0
4 V 0
5 E 1
6 S 1
7 V 1
8 D 1
9 H 0
您说您的实际数据实际上是按日期排序的,我想多个ID中的每个ID都有多个标志,因此类似的事情可能更现实:
create table your_table (id, flag_time, flag) as
select 1, timestamp '2018-07-04 00:00:00', 'E' from dual
union all select 1, timestamp '2018-07-04 00:00:01', 'V' from dual
union all select 1, timestamp '2018-07-04 00:00:02', 'H' from dual
union all select 1, timestamp '2018-07-04 00:00:03', 'V' from dual
union all select 1, timestamp '2018-07-04 00:00:04', 'E' from dual
union all select 1, timestamp '2018-07-04 00:00:05', 'S' from dual
union all select 1, timestamp '2018-07-04 00:00:06', 'V' from dual
union all select 1, timestamp '2018-07-04 00:00:07', 'D' from dual
union all select 1, timestamp '2018-07-04 00:00:08', 'H' from dual;
alter table your_table add active number;
merge into your_table
using (
select id, flag_time,
last_value(case when flag = 'E' then 1 when flag = 'H' then 0 end) ignore nulls
over (partition by id order by flag_time) as active
from your_table
) tmp
on (your_table.id = tmp.id and your_table.flag_time = tmp.flag_time)
when matched then update set active = tmp.active;
select * from your_table;
ID FLAG_TIME F ACTIVE
---------- ----------------------- - ----------
1 2018-07-04 00:00:00.000 E 1
1 2018-07-04 00:00:01.000 V 1
1 2018-07-04 00:00:02.000 H 0
1 2018-07-04 00:00:03.000 V 0
1 2018-07-04 00:00:04.000 E 1
1 2018-07-04 00:00:05.000 S 1
1 2018-07-04 00:00:06.000 V 1
1 2018-07-04 00:00:07.000 D 1
1 2018-07-04 00:00:08.000 H 0
主要区别是partition by id
并更改了使用flag_time
的顺序-或调用了任何实际列。
如果两个标志可以共享一个时间,则可能存在问题;带有时间戳列的字段希望不太可能,但是带有日期的列的精度可能允许它。但是,您对此无能为力,只能通过假设标志应该以一定顺序到达并以此为基础进行加权来打破平局。而是偏题。