使用触发器阻止数据库写入

时间:2018-08-06 00:45:51

标签: oracle plsql oracle11g triggers

我写了这个触发器来阻止数据库的写

create or replace trigger spese_autorizzate_trg
before insert or update on spese
for each row
declare 
    boolean integer := 0;
    voceSpesa tipospesa.descrizione%TYPE := NULL;

begin  
    select
        descrizione into voceSpesa
    from
        tipospesa
    where
        id = :new.tipospesa
        and approvazione = 'n';


    if voceSPesa is NULL then  
        raise_application_error(-20000, 'La spesa '||voceSpesa||' non è rimborsabile');
    end if;
end;

如果tipospesa的值为4或5,则应阻止书写 但是当我插入这样的行

insert into spese(id, importo, tipospesa, data) values (4, 20, 3, TO_DATE('15-jul-18', 'DD-MON-RR'))

我有这个错误

Error report:
SQL Error: ORA-01403: no data found
ORA-06512: at "PARLAMENTO2018.SPESE_AUTORIZZATE_TRG", line 7
ORA-04088: error during execution of trigger
'PARLAMENTO2018.SPESE_AUTORIZZATE_TRG'
01403. 00000 -  "no data found"
*Cause:    
*Action:

并且写作没有完成。为什么?

2 个答案:

答案 0 :(得分:0)

问题在于,如果表中没有返回任何行,则INTO子句将失败,从而引发no_data_found

如果没有行,可以使用

MAXMIN给您NULL

select
    MAX(descrizione) into voceSpesa
from
    tipospesa
where
    id = :new.tipospesa
    and approvazione = 'n';

请记住,在列descrizione本身为null的情况下,该字段也将为null。但是,这完全取决于您的要求,如果发生这种情况,您将如何处理。

答案 1 :(得分:0)

在我看来,您似乎必须处理NO_DATA_FOUND,而不是处理DESCRIZIONENULL的可能性。像这样:

create or replace trigger spese_autorizzate_trg
  before insert or update on spese
  for each row
declare 
    --  boolean integer := 0;              -- Uh, no! Boolean is name of PL/SQL datatype; 
                                           -- don't use it as name of a variable
                                           -- Besides, it is never used in your code.
    voceSpesa tipospesa.descrizione%TYPE;  -- No need to set it to NULL explicitly; 
                                           -- it is NULL anyway

begin  
  select descrizione 
    into voceSpesa
    from tipospesa
    where id = :new.tipospesa
      and approvazione = 'n';

exception
  when no_data_found then
    raise_application_error(-20000, 'La spesa '||voceSpesa||' non è rimborsabile');

  when too_many_rows then
    -- what then? Do you know? Can that select return more than a single row? If so,
    -- you should handle it
    null;
end;

是的,您可以使用select max(descrizione) ...保存一些键入内容,但这有点棘手。如果其他人继承了您的代码,他们是否会知道您使用MAX来避免NO_DATA_FOUND,或者您是否有意选择该列的最大值?因此,我想说最好是处理您期望的异常,并避免任何疑问。