2017-10-17 11 views
2

Je suis censé mettre à jour un élèves de première année à « A » basée sur la procédurePL/SQL Écrire une procédure pour mettre à jour une colonne?

ChangeGrade(p_sID, p_classID) 

Si l'étudiant ne participe pas à la classe (p_classID), alors un message d'erreur est imprimé.

Voici le tableau:

L'inscription

sID classID Grade 
*** ******* ***** 
104  10440  B 
102  10220  C 
...  .....  . 

Suis-je censé faire une jointure interne? Voici ce que j'ai:

Create or Replace ChangeGrade (
    p_sID enrolling.sID%type 
    p_classID enrolling.classID%type) 
AS 
    p_id_enrolled NUMBER; 

BEGIN 
    SELECT sID into p_id_enrolled 
    FROM Enrolling 
    WHERE sID = p_sID 
    AND classID = p_classID 

    IF p_sID = p_id_enrolled THEN 
    update Enrolling 
    set GRADE = 'A' 
    dbms_output.put_line('Student grade has been changed.') 
    ELSE 
    dbms_output.put_line('Student record does not exist.') 
    END IF; 
END; 
/ 
+0

Ainsi quelle est l'erreur. Quel problème avez-vous rencontré? 'dbms_output.put_line ('La note de l'étudiant a été modifiée.')' Le point-virgule est manquant à la fin. Il devrait être 'dbms_output.put_line ('La note de l'étudiant a été changée.');' – XING

+0

Obtenir une erreur à la ligne 7: Si p_sID = p_id_enrolled ALORS il est dit que la commande SQL n'a pas terminé correctement. À la ligne 2, SELECT sID dans p_id_enrolled indique que l'instruction SQL est ignorée. – Lizzie

+0

Chaque instruction en code PL/SQL doit être suivie de ';' – Dmitry

Répondre

1

Voici les problèmes dans votre code:

  1. Cette requête est dénuée de sens:

    SELECT sID into p_id_enrolled 
        FROM Enrolling 
        WHERE sID = p_sID 
        AND classID = p_classID 
    

    Vous sélectionnez sID dans p_id_enrolled, mais WHERE clause Filtrerez sID = p_sID, donc p_id_enrolled sera toujours égal à p_sID, et vous n'avez pas du tout besoin de cette instruction select.

  2. Cette déclaration de mise à jour met à jour toute la table:

    UPDATE Enrolling 
        SET GRADE = 'A'; 
    

    Vous devez ajouter une clause de filtrage pour mettre à jour une seule ligne.

  3. Dans un cas d'étudiant n'est pas inscrit en cours, la requête ne renvoie aucune ligne et vous obtiendrez l'exception NO_DATA_FOUND. Pour le traiter, vous devez attraper l'exception ou calculer le nombre d'élèves.

Je recommande d'utiliser ce qui suit:

Create or Replace procedure ChangeGrade (
    p_sID enrolling.sID%type, 
    p_classID enrolling.classID%type) 
AS 
    cnt NUMBER; 

BEGIN 
    SELECT count(*) into cnt 
    FROM Enrolling 
    WHERE sID = p_sID 
    AND classID = p_classID; 

    IF cnt = 1 THEN 
    update Enrolling 
     set GRADE = 'A' 
    where sID = p_sID 
     AND classID = p_classID; 
    dbms_output.put_line('Student grade has been changed.'); 
    ELSE 
    dbms_output.put_line('Student record does not exist.'); 
    END IF; 
END; 
/
+0

Vous dites "vous n'avez pas du tout besoin de cette instruction select" et "vous obtiendrez l'exception' NO_DATA_FOUND' ", puis vous incluez une instruction SQL et n'incluez pas l'exception sans aucune explication de la raison pour laquelle vous ne suivez pas Conseil. – MT0

+1

@ MT0 Merci, corrigé. En fait, ce n'est pas moi qui a manqué le mot-clé, je viens de copier le code de la question;) De plus, il y avait une virgule manquante après le premier paramètre de procédure. – Dmitry

+0

Je pense que la réponse n'est pas complètement correcte. Ce code 'SELECT count (*) dans cnt' donne une erreur laide,' ORA-01722: nombre invalide', lorsque l'étudiant n'est pas inscrit dans la classe. – Tenzin

0

Je ne sais pas quel type d'erreur est imprimé, mais il semble qu'il vous manque ';' à la fin de certaines commandes (dans l'instruction if et après select into).

+0

Obtention d'une erreur à la ligne 7: Si p_sID = p_id_enrolled ALORS il est indiqué que la commande SQL n'est pas correctement terminée. À la ligne 2, SELECT sID dans p_id_enrolled indique que l'instruction SQL est ignorée. – Lizzie

0

Comme mentionné dans mon commentaire, il y avait plusieurs endroits où semicolon (terminateur de ligne) manquait dans votre procédure. Essayez ceci:

CREATE OR REPLACE Procedure ChangeGrade (
    p_sID enrolling.sID%type 
    p_classID enrolling.classID%type) 
AS 
    p_id_enrolled NUMBER; 

BEGIN 
    SELECT sID 
    INTO p_id_enrolled 
    FROM Enrolling 
    WHERE sID = p_sID AND classID = p_classID; 

    IF p_sID = p_id_enrolled 
    THEN 
     UPDATE Enrolling 
     SET GRADE = 'A' 
     WHERE sID = p_sID; 

     DBMS_OUTPUT.put_line ('Student grade has been changed.'); 
    ELSE 
     DBMS_OUTPUT.put_line ('Student record does not exist.'); 
    END IF; 

EXCEPTION 
WHEN NO_DATA_FOUND Then 
dbms_output.put_line('Student record does not exist for this class'); 

END; 
/
+0

Vous n'obtiendrez jamais la sortie "L'enregistrement de l'étudiant n'existe pas" car la requête select lancera une exception 'NO_DATA_FOUND'. – MT0

+0

@ MT0 La question ne consistait pas à gérer l'exception plutôt que la raison pour laquelle l'Op obtenait une erreur. Comme d'habitude, vous essayez de penser au-delà de ce que OP a demandé, je n'ai pas de mots pour vous. Merci pour votre downvote. Voici un exemple https://stackoverflow.com/questions/46664130/error-catching-inside-plsql-block#comment80277180_46664130 – XING

+0

"Si l'étudiant n'est pas inscrit dans la classe (p_classID), un message d'erreur est imprimé." fait partie de la question - votre procédure ne fait pas cela. (et il vous manque le mot-clé 'PROCEDURE'). – MT0

1

Vous devez gérer le fait que l'étudiant n'est pas dans la classe comme une exception:

Create or Replace PROCEDURE ChangeGrade (
    p_sID enrolling.sID%type, 
    p_classID enrolling.classID%type, 
    p_grade enrolling.grade%type ) 
AS 
l_enrolled NUMBER; 

BEGIN 
    SELECT sID INTO l_enrolled 
    FROM Enrolling 
    WHERE sID = p_sID 
    AND classID = p_classID; 

    IF l_enrolled = p_sID THEN 
    update Enrolling set GRADE = p_grade WHERE sID = p_sID and classID = p_classID; 
    dbms_output.put_line('Student grade has been changed.'); 
    END IF; 

    EXCEPTION WHEN NO_DATA_FOUND 
    dbms_output.put_line('Student record does not exist for this class'); 
END; 
/ 

J'ai ajouté également un paramètre pour la qualité car il est logique de le transmettre comme bien.

+1

Il n'y a pas besoin de 'EXECUTE IMMEDIATE' ici. – Dmitry

+0

Vous avez raison, j'ai mis à jour ma réponse –

+0

Merci @ MT0. –

3
Create or Replace procedure ChangeGrade (
    p_sID enrolling.sID%type 
    p_classID enrolling.classID%type) 
AS 
BEGIN 
    update Enrolling 
    set GRADE = 'A' 
    where sID = p_sID 
    AND classID = p_classID; 
    IF SQL%ROWCOUNT > 0 THEN 
    dbms_output.put_line('Student grade has been changed.'); 
    ELSE 
    dbms_output.put_line('Student record does not exist.'); 
    END IF; 
END; 
+0

C'est la solution la plus simple, mais une petite explication de la raison pour laquelle le code OP ne fonctionnera pas serait bonne. – MT0

+0

@ MT0. Bloc d'exception s'il manque également ici. S'il vous plaît utiliser votre DOWNVOTE priv. – XING

+0

@XING Cette solution est correcte sans bloc de gestion des exceptions car elle effectue la mise à jour et vérifie que la mise à jour a mis à jour une ligne (en faisant correspondre la clé primaire) ou a mis à jour zéro ligne (lorsque l'étudiant n'est pas trouvé) lancera une exception 'NO_DATA_FOUND' car il n'utilise pas une instruction' SELECT'. – MT0

0

Vous pouvez également utiliser un curseur, puis voir si l'étudiant est inscrit à ce cours. Si c'est le cas, mettez à jour la note. Je pense qu'un curseur est plus sûr alors un SELECT X INTO n, parce que cela donne une erreur laide quand vous essayez d'insérer un NULL, SELECT NULL INTO n, et ces erreurs sont généralement difficiles à trouver.

Par exemple:

CREATE OR REPLACE ChangeGrade (p_sID enrolling.sID%TYPE, 
           p_classID enrolling.classID%TYPE) 
AS 
       CURSOR cEnrolling IS 
        SELECT  * 
        FROM  Enrolling 
        WHERE  SID = p_sID 
        AND  classID = p_classID; 

       rEnrolling cEnrolling%ROWTYPE; 
BEGIN 
     OPEN cEnrolling; 
     FETCH cEnrolling INTO rEnrolling; 
       IF cEnrolling%FOUND THEN 
         -- Student record found. 
         UPDATE Enrolling 
         SET Grade = 'A' 
         WHERE SID = rEnrolling.sId; 

         DBMS_OUTPUT.PUT_LINE('Student grade has been changed.'); 
       ELSE 
         -- Student record not found. 
         DBMS_OUTPUT.PUT_LINE('Student record does not exist.'); 
       END IF; 
     CLOSE cEnrolling; 
END; 
/