Как установить только для последней изменённой записи значение одного столбца?

Необходимо обеспечить существование в таблице единственной строки с определенным значением. То есть, чтобы при обновлении и добавлении записей занчение колонкаи текущей запии приобретало значение 1, а все оставшиеся - 0.

Попробовал сделать это триггером. С before insert все нормально. А вот что для update придумать? Или может есть какие-то еще варианты решения помимо триггеров?

Пример:

-- Создаем таблицу
create table tx (
  id integer,
  val varchar2(100)
);

-- Данные
-- truncate table tx

insert into tx
select level, 0 from dual connect by level < 11;

update tx set val = 1 where id = 5;
commit;

Добавляться может только 1 запись, обновляться тоже.

При добавлении и изменении надо:

  1. Проставлять прежней записи с val = 1 значение 0
  2. Для последней изменённой записи желательно принудительно установить val = 1.

Ответы (1 шт):

Автор решения: 0xdb

В качестве обходного пути решения предложу изменить таблицу:

create table t0 (id int, memo varchar2 (96), val char (1) not null)
/
alter table t0 drop column val
/
alter table t0 add (lastrow char (1) invisible, val char (1) as (nvl (lastrow, '0')) virtual) 
/
create index idxt0lastrow on t0 (lastrow)
/

Сушествующие запросы не заметят это изменение таблицы. Теперь, флаг последнего изменения будет хранится только для одной последней записи. Индекс для быстрого поиска с одной единсвенной записью, т.к. NULL значения не индексируются.

В составном триггере для update следует указать все столбцы, которые могут быть изменены, а lastrow во избежании рекурсивного вызова триггера, там должен быть опущен:

create or replace trigger t0lastrowtrig 
for insert or update of id,memo on t0 compound trigger 
    lastchanged rowid;  
    after each row is  
    begin  
        lastchanged := :new.rowid;
    end after each row;
    after statement is  
    begin 
        update t0 set 
            lastrow = case when lastrow is null then 1 end
        where rowid = lastchanged or lastrow=1;
    end after statement;  
end; 
/

Тест и результаты:

insert into t0 (id, memo) 
    select rownum, 'memo '||rownum from dual connect by level<10;
/
select * from t0
/   
        ID MEMO     VAL
---------- -------- ---
         1 memo 1   0  
[...]
         8 memo 8   0  
         9 memo 9   1  

update t0 set memo = memo||'*'
where id = 5
/
select * from t0
/
        ID MEMO     VAL
---------- -------- ---
         1 memo 1   0  
[...]
         5 memo 5*  1  
[...]
         9 memo 9   0
→ Ссылка