web-dev-qa-db-fra.com

Le tableau est en cours de mutation, le déclencheur/la fonction peut ne pas le voir (empêchant une note moyenne de descendre en dessous de 2,5)

Voici le problème:

Créez un déclencheur qui empêche toute modification de la relation de prise qui ferait passer la note moyenne globale dans une classe donnée en dessous de 2,5. Remarque: ce déclencheur n'est pas destiné à traiter la moyenne moyenne d'un étudiant donné, mais plutôt à la note moyenne de toutes les notes attribuées dans une classe donnée.

Voici le schéma:

Student-schema =(studentnum, name, standing, gpa, major)
Class-schema = (schedulenum, semester, department, classnum, days, time, place, enrollment)
Instructor-schema = (name, department, office)
Teaches-schema = (name, schedulenum, semester)
Taking-schema = (studentnum, schedulenum, semester, grade)

Je passe un mauvais moment avec ces déclencheurs, mais voici ma tentative pour que cela fonctionne:

CREATE OR REPLACE TRIGGER stopChange
    AFTER UPDATE OR INSERT OR DELETE ON taking
    REFERENCING OLD AS old
    NEW AS new
    FOR EACH ROW
DECLARE

grd_avg taking.grade%TYPE;

BEGIN
    SELECT AVG(grade)
    INTO grd_avg
    FROM taking
    WHERE studentnum = :new.studentnum
    AND schedulenum = :new.schedulenum
    AND semester = :new.semester;

    IF grd_avg < 2.5 THEN
        UPDATE taking
        SET grade = :old.grade
        WHERE studentnum = :old.studentnum
        AND schedulenum = :old.schedulenum
        AND semester = :old.semester;
    END IF;

END;   
/

Je fais évidemment quelque chose de mal parce que quand je vais ensuite mettre à jour ou supprimer un tuple, j'obtiens le message d'erreur:

ERROR at line 1:
ORA-04091: table TAKING is mutating, trigger/function may not see it
ORA-06512: at "STOPCHANGE", line 6
ORA-04088: error during execution of trigger 'STOPCHANGE'

Aucun conseil? J'utilise Oracle.

7
The Rationalist

Je pense que vous pouvez résoudre ce problème en réécrivant ceci en tant que déclencheur avant, plutôt que déclencheur après. Cependant, cela pourrait être un peu compliqué pour les insertions et les suppressions. L'idée est:

CREATE OR REPLACE TRIGGER stopChange
    BEFORE UPDATE OR INSERT OR DELETE ON taking
    REFERENCING OLD AS old
    NEW AS new
    FOR EACH ROW
DECLARE

grd_avg taking.grade%TYPE;

BEGIN
    SELECT (SUM(grade) - oldgrade + new.grade) / count(*)
    INTO grd_avg
    FROM taking
    WHERE studentnum = :new.studentnum
    AND schedulenum = :new.schedulenum
    AND semester = :new.semester;

    IF grd_avg < 2.5 THEN
        new.grade = old.grade
    END IF;
END;  
4
Gordon Linoff

utilisez cette déclaration dans DECLARE, cela fonctionnera.

pragma autonomous_transaction;
11
Sweta

Vous devez d’abord connaître les déclencheurs, l’erreur de table de mutation et les déclencheurs composés: http://docs.Oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005

Votre déclencheur est AFTER UPDATE OR INSERT OR DELETE. Cela signifie que si vous exécutez les instructions UPDATE OR INSERT OR DELETE sur cette table, le déclencheur se déclenchera. Mais vous essayez de mettre à jour la même table à nouveau dans votre déclencheur, ce qui est compl. faux. C'est pourquoi vous obtenez l'erreur. Vous ne pouvez pas modifier la même table sur laquelle le déclencheur est activé. Le déclencheur a pour but de se déclencher automatiquement lorsque la table est mise à jour, insérée ou supprimée dans votre cas. Ce dont vous avez besoin est une procédure, pas un déclencheur.

6
Art

Même nous avons fini avec le même problème dans notre projet. Mais après avoir cherché dans quelques forums Oracle, nous avons trouvé la solution ci-dessous.

1) Enregistrez les données de l'ancienne/nouvelle colonne dans une table temporaire sous forme de pat du déclencheur de niveau ligne . 2) Écrivez un déclencheur de niveau instruction et utilisez les données enregistrées à l'étape 1.

Cela résoudrait le problème, je pense.

0
user2988234

J'ai eu le même problème et j'ai remarqué que si vous faites un select sur la même table, vous mettez/vous obtiendrez ce problème . Vous pouvez supprimer FOR EACH ROW Ou utiliser le données dans: Nouveau pour effectuer le calcul (si possible) puis effectuer la mise à jour.

Dans votre cas, il serait plus judicieux d'utiliser une table distincte pour obtenir la moyenne moyenne par semestre.

0
acostil