2017-10-14 11 views
0

Je fais cet exercice pour l'université et je suis bloqué depuis une semaine. J'ai besoin de créer un déclencheur de sorte que lorsque la colonne d'état sur la table "tbvale" est modifiée, quelques mises à jour se produisent sur la colonne "tbfuncionario" en conséquence. Je me rends compte que mon code semble probablement lourd et même inapproprié, mais c'est un exercice uni conçu pour enseigner des choses spécifiques. C'est ce que je suis venu avec à ce jour:Déclencheur Oracle PL/SQL qui met à jour une table différente

CREATE OR REPLACE TRIGGER status_chg 
AFTER UPDATE OF status ON tbvale 
FOR EACH ROW 
DECLARE 
    nvd tbfuncionario.numvalesdescontados%type; 
    nva tbfuncionario.numvalesaberto%type; 
    vtva tbfuncionario.valortotalvalesaberto%type; 
    nve tbfuncionario.numvalesemitidos%type; 
    vv tbvale.valorvale%type; 
    cod tbvale.fkcodmat%type; 
    pragma autonomous_transaction; 
BEGIN 
    IF (:NEW.status <> :OLD.status) THEN 
     SELECT valorvale INTO vv FROM tbvale; 
     SELECT fkcodmat INTO cod FROM tbvale; 
     IF (:NEW.status = 2) THEN 
      nvd := 1; 
      nva := -1; 
      nve := 0; 
      vv := vv - 1; 
     ELSE 
      nvd := 0; 
      nve := 1; 
      nva := 1; 
      vv := vv + 1; 
     END IF; 
     UPDATE tbfuncionario 
     SET numvalesdescontados = numvalesdescontados + nvd, 
      numvalesaberto = numvalesaberto + nva, 
      numvalesemitidos = numvalesemitidos + nve, 
      valortotalvalesaberto = valortotalvalesaberto + vv 
     WHERE pkcodmat = cod; 
    END IF; 
END; 

pkcodmat est le PK de tbfuncionario et fkcodmat est le FK de pkcodmat référencement de tbvale.

Actuellement quand je lance

UPDATE tbvale SET STATUS = 2 WHERE PKCODVALE = 3; 

Je reçois l'erreur suivante:

ERROR: ORA-01422: exact fetch returns more than requested 
number of rows ORA-06512: at "ULBRA.STATUS_CHG", line 11 
ORA-04088: error during execution of trigger 'ULBRA.STATUS_CHG' 

Error Code: 1422 

Query = UPDATE tbvale SET STATUS = 2 WHERE PKCODVALE = 3 

Je ne comprends pas pourquoi il serait « retour plus que le nombre requis de lignes » comme il n'y a qu'un seul row où pkcodmat est égal à fkcodmat.

J'apprécie tout aperçu de la raison pour laquelle cela se produit et comment je pourrais le réparer.

+0

ajouter une clause where aux instructions select dans le corps de la détente. – DwB

+0

Ces requêtes doivent renvoyer une seule ligne: 'SELECT VALEURALE INTO vv FROM tbvale;' 'SELECT fkcodmat DANS LA morue FROM tbvale;' – L30n1d45

+0

"'Je suis resté bloqué pendant une semaine" Si vous aviez lancé 'SELECT valorvale FROM tbvale;' sur son possédez vous pourriez vous avoir sauvé six jours, vingt-trois heures et cinquante-neuf jours de coincement. ' – APC

Répondre

1

Vous n'avez pas besoin de ces requêtes qui sont à l'origine l'exception:

SELECT valorvale INTO vv FROM tbvale; 
SELECT fkcodmat INTO cod FROM tbvale; 

En supposant que vous voulez que les valeurs de la tbvale ligne étant mis à jour, utilisez le :old ou :new enregistrement comme par exemple approprié

vv := :new.valorvalue; 
cod := :new.fkcodmat; 
+0

Merci! Cela semble fonctionner. Je vais faire quelques tests pour être sûr mais jusqu'ici tout va bien! – pharaohlxvi

2

Le déclencheur semble assez bon. Voici quelques points:

  1. IF (:NEW.status <> :OLD.status) ne détecte pas sous forme de changements et à NULL, dans le cas où la colonne est annulable. Plutôt que IF à l'intérieur du corps, j'utiliserais plutôt la clause déclencheurs WHEN.
  2. Vous utilisez des types de colonne pour les variables. Cependant, ceux-ci ne sont supposés contenir que des entiers. Pas besoin donc pour les types de colonnes.
  3. SELECT valorvale INTO vv FROM tbvale, Cela ne fonctionne pas. Vous voulez la valeur d'une ligne, vous aurez donc besoin d'une clause WHERE. Mais comme vous êtes censé être intéressé par la valeur actuelle des enregistrements, vous pouvez simplement utiliser .
  4. Idem pour SELECT fkcodmat INTO cod FROM tbvale. Un déclencheur autonome nécessite ou ROLLBACK à la fin.

Voici le déclencheur corrigé:

CREATE OR REPLACE TRIGGER status_chg 
AFTER UPDATE OF status ON tbvale 
FOR EACH ROW 
WHEN (DECODE(NEW.STATUS, OLD.STATUS, 0, 1) = 1) 
DECLARE 
    v_vd integer; 
    v_va integer; 
    v_ve integer; 
    v_vv tbvale.valorvale%type; 
    PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN 
    IF (:NEW.status = 2) THEN 
    v_vd := 1; 
    v_va := -1; 
    v_ve := 0; 
    v_vv := :NEW.valorvale - 1; 
    ELSE 
    v_vd := 0; 
    v_va := 1; 
    v_ve := 1; 
    v_vv := :NEW.valorvale + 1; 
    END IF; 

    UPDATE tbfuncionario 
    SET numvalesdescontados = numvalesdescontados + v_vd, 
     numvalesaberto = numvalesaberto + v_va, 
     numvalesemitidos = numvalesemitidos + v_ve, 
     valortotalvalesaberto = valortotalvalesaberto + v_vv 
    WHERE pkcodmat = :NEW.fkcodmat; 

    COMMIT; 
END; 

Et voici le même déclencheur sans variables:

CREATE OR REPLACE TRIGGER status_chg 
AFTER UPDATE OF status ON tbvale 
FOR EACH ROW 
WHEN (DECODE(NEW.STATUS, OLD.STATUS, 0, 1) = 1) 
DECLARE 
    PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN 
    UPDATE tbfuncionario 
    SET numvalesdescontados = numvalesdescontados + CASE WHEN :NEW.status = 2 THEN 1 ELSE 0 END 
    , numvalesaberto = numvalesaberto + CASE WHEN :NEW.status = 2 THEN -1 ELSE 1 END 
    , numvalesemitidos = numvalesemitidos + CASE WHEN :NEW.status = 2 THEN 0 ELSE 1 END 
    , valortotalvalesaberto = valortotalvalesaberto + :NEW.valorvale + CASE WHEN :NEW.status = 2 THEN -1 ELSE 1 END 
    WHERE pkcodmat = :NEW.fkcodmat; 

    COMMIT; 
END; 
+0

Salut, merci pour votre réponse. Je comprends les changements que vous avez faits. Il y a une erreur cependant que j'ai faite en copiant mon code. La valeur de: NEW.valorvale devrait être soustraite ou ajoutée à valortotalvalesaberto plutôt que d'ajouter ou de soustraire 1 (pas sûr que je me suis fait clair). C'est facile à corriger avec un (*) au lieu d'un (+), n'est-ce pas? (valortotalvalesaberto = valortotalvalesaberto +: NEW.valorvale * CAS LORSQUE: NEW.status = 2 THEN -1 ELSE 1 END). Autre que cela quand j'ai essayé votre code j'ai eu "ERREUR: ORA-00906: parenthèse gauche manquante". – pharaohlxvi

+0

Oui, votre solution avec un facteur fonctionne bien. Une alternative est '= valortotalvalesaberto + CASE WHEN: NEW.status = 2 ALORS -: NEW.valorvale ELSE: NEW.valorvale END'. Désolé pour les parenthèses manquantes; la clause WHEN en a besoin. J'ai mis à jour ma réponse. –

+0

Ça marche! Merci beaucoup! – pharaohlxvi