简体   繁体   中英

ORACLE PL/SQL Update another table value on insert

I am trying to create a trigger on any insert or update on a table which holds Diseases with animalName and diseaseName . I have another table, Animals , which holds informations like the animalName (which is a primary key; don't comment on the design as it is not mine), and the amountOfDisease he had. I want that, upon insert, update or delete in the Diseases table, the amount of Diseases is automatically updated.

I have a hard time understanding how I can obtain the current animalName so that I can update his amountOfDisease .

So far, I have this :

CREATE OR REPLACE TRIGGER update_animal_diseases
AFTER INSERT OR UPDATE OR DELETE ON Diseases
FOR EACH ROW
BEGIN
    UPDATE Animals SET amountOfDisease = amountOfDisease + 1 
WHERE animalName = :NEW.animalName;
END;
/

Which compile but doesn't work, as the values in Animals never get updated on inserting something into Diseases . I also tried this :

CREATE OR REPLACE TRIGGER update_animal_diseases
AFTER INSERT OR UPDATE ON Diseases
FOR EACH ROW
DECLARE
DiseasesCount   INTEGER;
BEGIN
    SELECT COUNT(*) INTO DiseasesCount
    FROM Diseases
    WHERE animalName = :OLD.animalName;

    UPDATE Animals SET amountOfDisease = DiseasesCount WHERE animalName = :OLD.animalName;
END;
/

As you can see I also don't really understand what the :NEW and :OLD are. How can I solve my problem, which is to update an animal amountOfDisease on any modification of the Diseases table ?

To be clear, what I get on INSERT-ing into Diseases is just nothing. Nothing happens as far as I can tell.

I see two possible causes.

  1. In the first version you are always adding +1, even on delete.

  2. Also if amountofdisease field is null on a record after adding +1 it will null anyway.

Maybe something like this should work for you.

Tables:

CREATE TABLE animals
(  animalname        VARCHAR2 (10),
   amountofdisease   NUMBER);

CREATE TABLE diseases
(  animalname    VARCHAR2 (10),
   diseasename   VARCHAR2 (20));

Trigger:

CREATE OR REPLACE TRIGGER apps.diseases_aiud1
   BEFORE DELETE OR INSERT OR UPDATE
   ON diseases
   REFERENCING NEW AS new OLD AS old
   FOR EACH ROW
DECLARE
BEGIN
   IF INSERTING
   THEN
      UPDATE animals
         SET amountofdisease = NVL (amountofdisease, 0) + 1
       WHERE animalname = :new.animalname;
   ELSIF DELETING
   THEN
      UPDATE animals
         SET amountofdisease = NVL (amountofdisease, 0) - 1
       WHERE animalname = :old.animalname;
   ELSIF UPDATING
   THEN
      UPDATE animals
         SET amountofdisease = NVL (amountofdisease, 0) + 1
       WHERE animalname = :new.animalname;

      UPDATE animals
         SET amountofdisease = NVL (amountofdisease, 0) - 1
       WHERE animalname = :old.animalname;
   END IF;
END diseases_aiud1;
/

Note de use of :new and :old depending on the event.

Loading sample animals:

insert into animals values ('jaguar',0);
insert into animals values ('capibara',0);
insert into animals values ('fox',0);
commit;

Test 1 Insert

insert into diseases values
('jaguar','pneumonia');
insert into diseases values
('jaguar','epistaxis');
commit;

select *
from animals;

Result 1:

1 row created.
1 row created.
Commit complete.

ANIMALNAME AMOUNTOFDISEASE
---------- ---------------
jaguar                   2
capibara                 0
fox                      0

3 rows selected.

Test 2 delete:

delete from diseases
where animalname = 'jaguar' and diseasename = 'pneumonia'
;
insert into diseases values
('fox','hydrophobia');

Result 2:

ANIMALNAME AMOUNTOFDISEASE
---------- ---------------
jaguar                   1
capibara                 0
fox                      1

Test 3 Update:

update diseases
set animalname = 'capibara'
where animalname = 'fox';

Result 3:

ANIMALNAME AMOUNTOFDISEASE
---------- ---------------
jaguar                   1
capibara                 1
fox                      0

As a side note it should be recommended to write a package in order to handle this logic. Triggers are tricky, hardest to maintain and can lead to unexpected results in some scenarios.

Regards,

If I had to speculate, you don't have matching rows in Animals for all animals in Diseases . You can find these by doing:

select d.*
from diseases d
where not exists (select 1 from animals a where a.animal = d.animal);

If this is the case, then you should structure the database to have an explicit foreign key relationship from diseases to animals . This will ensure that only valid animals are in the table.

As far as trigger,
:NEW means when New record in inserted to your primary table(primary table here means a table where you sets triggers on insert) it takes always New I'd to insert record related records as per trigger in relative table (relative table means in trigger you defined to insert / update record when primary table effected. )
:OLD means in relative table it takes last inserted I'd as new id in relative table. It can be use as foriegn key in second table.
I hope it's meaning full for your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM