PL/SQL 写一个更新列的程序?

PL/SQL Write a procedure to update a column?

我应该根据程序

将学生成绩更新为 'A'
ChangeGrade(p_sID, p_classID)

如果学生未在 class (p_classID) 中注册,则会打印一条错误消息。

这里是 table:

正在注册

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

我不知道打印出什么样的错误,但你好像漏掉了';'在某些命令的结尾(在 if 语句中和 select 之后)。

正如我在评论中提到的,您的程序中有几个地方缺少 semicolon(行终止符)。试试这个:

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

您需要将学生不在 class 中的事实作为例外处理:

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. 这个查询没有意义:

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

    你 select sID 变成了 p_id_enrolled,但是在 WHERE 子句中你过滤了 sID = p_sID,所以 p_id_enrolled 总是等于p_sID,你根本不需要这个 select 语句。

  2. 这条更新语句更新整个table:

    UPDATE Enrolling
       SET GRADE = 'A';
    

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

  3. 如果学生没有在 class 注册,查询 returns 没有行,你会得到 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;
/
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;

您也可以使用光标,然后查看学生是否注册了该课程。如果 he/she 是,则更新成绩。我认为游标比 SELECT X INTO n 更安全,因为当您尝试插入 NULLSELECT 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;
/