«Я даже не уверен, что это хорошая практика».
Ваша интуиция права: это является плохой практикой. По какой-то причине многие профессора колледжа ставят перед своими учениками задачу написания плохого кода; это не было бы так плохо, если бы они, по крайней мере, объяснили, что это плохая практика и никогда не должна использоваться в реальном мире. Но тогда я думаю, что большинство профессоров имеют ограниченное представление о том, что имеет значение в реальном мире. Вздох .
Anyhoo, чтобы ответить на ваш вопрос. Есть два подхода к этому. Можно было бы использовать триггер, чтобы «исправить», то есть проглотить изменение. Это было бы неправильно, потому что пользователь, пытающийся изменить значение, вероятно, потратил бы много времени, пытаясь выяснить, почему его изменение не прилипало, не осознавая, что он нарушает бизнес-правило. Так что гораздо лучше выкинуть исключение.
В этом примере используется синтаксис Oracle, потому что я предполагаю, что это то, что вы используете.
create or replace trigger order_header_trg
before insert or update
on order_header for each row
begin
if :new.order_total != :old.order_total
then
raise_application_error
( -20000, 'You are not allowed to modify the value of ORDER_TOTAL');
end if;
end;
Единственная проблема этого подхода заключается в том, что он не позволит вам вставить строки в ORDER_LINES и затем получить новый итог для ORDER_HEADER.
Это одна из причин, по которой денормализованные итоги являются плохой практикой.
Ошибка, которую вы получаете - ORA-04091 - говорит "таблица мутаций". Это происходит, когда мы пытаемся написать триггер, который выбирает из таблицы, которой принадлежит триггер. Это почти всегда указывает на плохую модель данных, которая недостаточно нормализована. Это, очевидно, случай здесь.
Учитывая, что вы застряли с моделью данных, единственным обходным решением является неуклюжая реализация, использующая несколько триггеров и пакет. Интернет предлагает различные решения: , вот один .