更新有延迟

Update with lag

我想将 table 的 ACTIVE 值设置如下:

依此类推。

例子

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。

您可以通过 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

db<>fiddle demo.


你说你的真实数据实际上是按日期排序的,我猜多个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 - 或者任何您真正的列的名称。

db<>fiddle demo.


如果两个标志可以共享一个时间,则可能存在问题;带有希望不太可能的时间戳列,但是带有日期的列的精度可能允许它。但是,您对此无能为力,除了可能通过假设标志应按特定顺序到达并根据该顺序赋予它们权重来进入某种逻辑来打破平局。不过有点跑题了。