2017-10-17 88 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; 
/
相關問題