Обновление с задержкой - PullRequest
0 голосов
/ 05 июля 2018

Я бы хотел установить АКТИВНОЕ значение таблицы следующим образом:

  • Если 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

Значение упорядочено по дате. Для простоты я добавил столбец идентификаторов, чтобы получить порядок столбцов.

Вопрос

Что может быть оператором обновления SQL?

Примечание:

Бизнес-правило также может быть выражено следующим образом:

Если для данной строки количество предшествующих E - количество предшествующих H равно 1, то ACTIVE равно 1 для этой строки, в противном случае - 0.

1 Ответ

0 голосов
/ 05 июля 2018

Вы можете получить значение active с помощью аналитической функции last_value() :

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 .


Вы сказали, что ваши реальные данные упорядочены по дате, и я предполагаю, что для каждого из нескольких идентификаторов есть несколько флагов, поэтому что-то вроде этого, вероятно, более реалистично:

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 .


Существует потенциальная проблема, если два флага могут совместно использовать время; с столбцом метки времени, который, мы надеемся, очень маловероятен, но с датой точность столбца может это позволить. Однако с этим мало что можно поделать, за исключением, может быть, некоторой логики разрыва связей, предполагая, что флаги должны поступать в определенном порядке, и присваивать им вес, основанный на этом. Скорее не по теме.

...