PLSQL触发器-在插入新记录之前更新另一个表

时间:2019-12-02 14:32:57

标签: oracle plsql

我有3个彼此相关的表:

  • ACCOUNTS
  • CARDS
  • TRANSACTIONS

我想在每次执行新交易时从帐户中更改金额。我想随着每一次新动作降低帐户价值。

我尝试编写此触发器:

create or replace trigger ceva_trig1
before insert on miscari
for each row
declare
  new_val micari.valoare%tipe := new.valoare;
begin
  update conturi
  set    sold = sold - new_val
  where  nrcont = (select nrcont
                   from   conturi
                          join carti_de_credit on conturi.nrcont = carti_de_credit.nrcont
                          join miscari on carti_de_credit.nr_card = miscari.nrcard)
  and sold >= new_val; 
end;

有人可以帮助我纠正此处崩溃的语法吗?

2 个答案:

答案 0 :(得分:3)

我创建了具有最少列数的表,只是为了进行触发器编译。

SQL> create table conturi
  2    (sold   number,
  3     nrcont number
  4    );

Table created.

SQL> create table miscari
  2    (valoare number,
  3     nrcard  number
  4    );

Table created.

SQL> create table carti_de_credit
  2    (nrcont  number,
  3     nr_card number
  4    );

Table created.

触发:

SQL> create or replace trigger ceva_trig1
  2    before insert on miscari
  3    for each row
  4  begin
  5    update conturi c
  6    set    c.sold = c.sold - :new.valoare
  7    where  c.nrcont = (select r.nrcont
  8                         from carti_de_credit r
  9                         where r.nrcont = c.nrcont
 10                           and r.nr_card = :new.nrcard
 11                      )
 12      and c.sold >= :new.valoare;
 13  end;
 14  /

Trigger created.

SQL>

它与您的代码有何不同?像这样:

SQL> create or replace trigger ceva_trig1
  2  before insert on miscari
  3  for each row
  4  declare
  5    new_val micari.valoare%tipe := new.valoare;
  6  begin
  7    update conturi
  8    set    sold = sold - new_val
  9    where  nrcont = (select nrcont
 10                     from   conturi
 11                            join carti_de_credit on conturi.nrcont = carti_de_credit.nrcont
 12                            join miscari on carti_de_credit.nr_card = miscari.nrcard)
 13    and sold >= new_val;
 14  end;
 15  /

Warning: Trigger created with compilation errors.

SQL> show err
Errors for TRIGGER CEVA_TRIG1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
2/11     PL/SQL: Item ignored
2/26     PLS-00208: identifier 'TIPE' is not a legal cursor attribute
4/3      PL/SQL: SQL Statement ignored
10/15    PL/SQL: ORA-00904: "NEW_VAL": invalid identifier
10/15    PLS-00320: the declaration of the type of this expression is incomplete or malformed

SQL>

解释:

  • 不是tipe,而是type
  • 新列值用冒号引用,即:new.valoare
  • 您不应在表和列名称上打错字;是miscari,而不是micari
  • 不好的做法是编写引用为其创建触发器的表(miscari,第12行)的查询。由于它正在更改,因此您不能从中选择值,因为它是变异
    • 幸运的是,您根本不需要这样做。怎么样?看看我的代码。

答案 1 :(得分:0)

试图在另一个表中的一个表中保持事务的持续进行始终是一个坏主意。诚然,在极少数情况下这是必要的,但应该是万不得已的设计,而不是最初的设计。即使在必要时,这仍然不是一个好主意,因此需要更多的处理和复杂性。
在这种情况下,在纠正了所有错误后@Littlefoot指出了问题,然后才是真正的问题。在以下情况下您该怎么办:(使用Littlefoot的表定义)

  • 我要从miscari中删除一行吗?
  • 我在miscari中更新了一行吗?
  • nrcont的子选择返回0行吗?
  • 出售的条件> = new_val是否为假?

如果发生任何情况,按conturi出售的价值不正确,并且可能无法根据来源表中的价值进行修正-miscari。该列表可能只是您面临的问题的开始。

建议:放弃保持交易价值连续账户的想法。而是在需要时派生它。您可以创建一个执行该操作的视图,然后从该视图中进行选择。
 因此,也许不是“创建表conturi ...”