как сделать сообщение после обновления значения без отмены обновления - PullRequest
0 голосов
/ 06 апреля 2019

Я должен проверить, что обновление заметки не уступает 10% с помощью триггера.если оно больше 10%, я должен настроить его на 10% и написать сообщение об ошибке, а если новая заметка меньше 0, я должен установить ее на 0

, когда я пытаюсь поднять ошибкуэто просто отменаи мой вариант заказа СУБД не работает, обновление выполняется с хорошим значением, но без сообщения

CREATE OR REPLACE TRIGGER C3_update
BEFORE UPDATE OF note on Inscription
FOR EACH ROW
WHEN (NEW.note < OLD.note*0.9)
begin
    if(:NEW.note > 0) then
    :NEW.note := :OLD.note*0.9;
    dbms_output.enable;
    dbms_output.put_line ('la note ne peut descendre de plus de 10%');
    --or
    --RAISE_APPLICATION_ERROR(-20111,'the note can not be less than 10%');
    end if;

    if(:NEW.note < 0) then 
    :NEW.note := 0;
    RAISE_APPLICATION_ERROR(-20011,'the note can not be under 0');
    end if;
  end;
  /

Я хотел бы установить примечание и напечатать сообщение об ошибке сразу, я просто отменяю обновление или обновляюобратите внимание на хороший способ, но сообщение не печатать

1 Ответ

0 голосов
/ 06 апреля 2019

С моей точки зрения, это неправильный подход. Бизнес-правило не должно применяться триггером базы данных. На вашем месте я бы поместил его во внешнее приложение (там же, где вводится новое значение заметки).

Таким образом, вы даже сможете уведомить пользователя о том, что происходит, и позволить ему решить, хотят ли они принять новое значение (которое вы предложите, исходя из этих условий), или нет (и, возможно, введите новое действительное значение).

Как вы заметили, DBMS_OUTPUT.PUT_LINE не работает. Было бы, если инструмент, который вы используете для обновления значения примечания, способен отображать его. (Кстати, вы SET SERVEROUTPUT ON?) Если вы используете, например, Oracle Forms, вы бы увидели ничего .

RAISE_APPLICATION_ERROR, при вызове завершает подпрограмму и возвращает пользовательский номер ошибки и сообщение . Тем не менее, это также отменяет обновление, которое вы делаете. Даже если вы установите триггер как автономную транзакцию, он не будет работать. Например:

SQL> drop table inscription;

Table dropped.

SQL> create table inscription (note number);

Table created.

SQL> insert into inscription (note) values (2);

1 row created.

SQL> create or replace trigger c3_update
  2    before update of note on inscription
  3    for each row
  4    when (new.note < old.note * 0.9)
  5  declare
  6    pragma autonomous_transaction;
  7    l_note inscription.note%type;
  8    l_info varchar2(100);
  9  begin
 10    if :new.note > 0 then
 11       :new.note := :old.note * 0.9;
 12       l_info := 'the note can not be less than 10%';
 13    elsif :new.note < 0 then
 14       :new.note := 0;
 15       l_info := 'the note can not be under 0';
 16    end if;
 17    -- Let's hope that COMMIT will save the updated value
 18    select note into l_note from inscription;
 19    dbms_output.put_line('Note before commit = ' || l_note);
 20    commit;
 21    select note into l_note from inscription;
 22    dbms_output.put_line('Note after commit = ' || l_note);
 23
 24    -- Raise the "error", hoping that it'll just display a message,
 25    -- but updated value will remain "as is"
 26    raise_application_error(-20001, l_info);
 27  end;
 28  /

Trigger created.

SQL> set serveroutput on
SQL> update inscription set note = -1;
Note before commit = 2
Note after commit = 2
update inscription set note = -1
       *
ERROR at line 1:
ORA-20001: the note can not be under 0
ORA-06512: at "SCOTT.C3_UPDATE", line 22
ORA-04088: error during execution of trigger 'SCOTT.C3_UPDATE'


SQL> select * from inscription;

      NOTE
----------
         2

См? Вместо 0 примечание сохраняет свое первоначальное значение (2). Он даже не получил значение 0, потому что триггер не завершился успешно. Как это проверить? Комментируя команду RAISE:

SQL> create or replace trigger c3_update
  2    before update of note on inscription
  3    for each row
  4    when (new.note < old.note * 0.9)
  5  declare
  6    pragma autonomous_transaction;
  7    l_note inscription.note%type;
  8    l_info varchar2(100);
  9  begin
 10    if :new.note > 0 then
 11       :new.note := :old.note * 0.9;
 12       l_info := 'the note can not be less than 10%';
 13    elsif :new.note < 0 then
 14       :new.note := 0;
 15       l_info := 'the note can not be under 0';
 16    end if;
 17    -- Let's hope that COMMIT will save the updated value
 18    select note into l_note from inscription;
 19    dbms_output.put_line('Note before commit = ' || l_note);
 20    commit;
 21    select note into l_note from inscription;
 22    dbms_output.put_line('Note after commit = ' || l_note);
 23
 24    -- Raise the "error", hoping that it'll just display a message,
 25    -- but updated value will remain "as is"
 26    --raise_application_error(-20001, l_info);
 27  end;
 28  /

Trigger created.

SQL> set serveroutput on
SQL> update inscription set note = -1;
Note before commit = 2
Note after commit = 2

1 row updated.

SQL> select * from inscription;

      NOTE
----------
         0

Это выполняет работу, но - сообщение не может быть отображено (я уже говорил вам, почему).

Если вы намеревались включить UPDATE inscription set note = its_new_value в сам триггер, не делайте - вы получите тупик, поскольку первоначальное обновление запускает триггер, который выполняет обновление, которое вызывает триггер, который выполняет обновление и т. Д.

Поэтому, насколько я могу судить, вы не можете делать то, что хотите, не с помощью триггера.

...