2017-10-17 75 views
2

我应该更新年级学生根据程序PL/SQL编写一个过程来更新列?

ChangeGrade(p_sID, p_classID) 

如果学生没有在类(p_classID)就读“A”则打印错误消息。

下面是表:

招生报名

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

我应该做一个内部联接?这是我有什么:

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

所以什么错误。你面临什么问题? 'dbms_output.put_line('学生成绩已被更改'。)'最后缺少分号。它应该是 'dbms_output.put_line('学生成绩已被更改');' – XING

+0

在第7行得到错误:如果p_sID = p_id_enrolled那么它表示SQL命令没有正确结束。在第2行,SELECT sID到p_id_enrolled中,它表示SQL语句被忽略。 – Lizzie

+0

PL/SQL代码中的每个语句都必须后面跟着'; – Dmitry

回答

1

这里是你的代码中的问题:

  1. 这个查询是没有意义的:

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

    您选择sIDp_id_enrolled,但在WHERE条款您筛选sID = p_sID,所以p_id_enrolled总是会等于p_sID,并且根本不需要此选择语句。

  2. 此更新语句将更新整个表:

    UPDATE Enrolling 
        SET GRADE = 'A'; 
    

    您需要添加一个过滤子句只更新一行。

  3. 如果学生没有在课程中注册,则查询不会返回任何行,您将得到NO_DATA_FOUND例外。要处理它,你需要捕捉异常或计算学生数量。

我会建议使用下列内容:

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

你说“你根本不需要这个select语句”和“你会得到'NO_DATA_FOUND'异常”,然后你包含一个SQL语句,并且不包含这个异常,并且没有任何解释你为什么不跟随你自己咨询。 – MT0

+1

@ MT0谢谢,更正。实际上,不是我错过了关键字,我刚刚从问题中复制了代码;)另外,第一个过程参数后面还有一个逗号。 – Dmitry

+0

我认为答案并不完全正确。当学生没有入学时,这段代码“SELECT count(*)into cnt'给出了一个丑陋的错误'ORA-01722:invalid number'。 – Tenzin

0

我不知道打印出哪种错误,但它似乎像你缺少';'在一些命令的结尾处(在if语句和select into之后)。

+0

在第7行获取错误:如果p_sID = p_id_enrolled那么它表示SQL命令未正确结束。在第2行,SELECT sID到p_id_enrolled中,它表示SQL语句被忽略。 – Lizzie

0

正如我在评论中提到的,在您的程序中有几个地方semicolon(line termator)缺失。试试这个:

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

你将永远不会得到“学生记录不存在”的输出,因为select查询会抛出一个'NO_DATA_FOUND'异常。 – MT0

+0

@ MT0问题不是为了处理异常,而是为什么Op会出错。像往常一样,你试图超越OP要求的想法,我对你没有任何话语。感谢您的downvote。这里是一个示例https://stackoverflow.com/questions/46664130/error-catching-inside-plsql-block#comment80277180_46664130 – XING

+0

“如果学生没有在类中注册(p_classID),​​则会打印一条错误消息。”是问题的一部分 - 你的程序不这样做。 (并且你错过了'PROCEDURE'关键字)。 – MT0

1

您需要处理的事实,学生是不是在类为例外:

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; 
/ 

我还添加了等级的参数,因为它的逻辑把它作为好。

+1

这里没有必要在'EXECUTE IMMEDIATE'中。 – Dmitry

+0

你说得对,我更新了我的回答 –

+0

谢谢@ 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

这是最简单的解决方案,但是为什么OP的代码不起作用会有所帮助。 – MT0

+0

@ MT0。如果在这里丢失了异常块。请使用您的DOWNVOTE权限。 – XING

+0

@XING该解决方案在没有异常处理块的情况下是正确的,因为它执行更新并检查更新是否已更新行(通过匹配主键)或已更新零行(未找到学生时) - 两种可能性会抛出一个'NO_DATA_FOUND'异常,因为它不使用'SELECT'语句。 – MT0

0

你也可以使用一个光标,然后看如果学生在课程就读。如果他/她是,则更新等级。我认为光标更安全,然后是SELECT X INTO n,因为当您尝试插入NULL,SELECT NULL INTO n时确实会出现一个难看的错误,而且这些错误通常很难找到。

例如:

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; 
/