Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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;

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;

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.

@GordonLinoff As I said in the end of the post, nothing happens, values are not updated correctly. – user96649 Oct 21, 2017 at 13:30
  • In the first version you are always adding +1, even on delete.

  • 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
          UPDATE animals
             SET amountofdisease = NVL (amountofdisease, 0) + 1
           WHERE animalname = :new.animalname;
       ELSIF DELETING
          UPDATE animals
             SET amountofdisease = NVL (amountofdisease, 0) - 1
           WHERE animalname = :old.animalname;
       ELSIF UPDATING
          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.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.