2017-11-29 12 views
1

두 곳에서 예외 섹션을 사용하여 학생 번호가 유효하지 않은 경우 프로그램에서 오류를 인쇄하도록해야합니다. 하나는 주 절차에, 다른 하나는 하위 프로그램에 있습니다.PLSQL 예외 처리

하위 프로그램의 예외는 실행되지만 주 프로그램은 실행되지 않도록 오류를 만드는 방법은 무엇입니까?

CREATE OR REPLACE PROCEDURE validate_student(
    p_snum IN students.snum%TYPE, 
    p_student_error out VARCHAR2) AS 

    v_snum students.snum%TYPE; 

BEGIN 
    --count the number of student with id p_snum and assign it to v_snum 
    SELECT count(snum) INTO v_snum 
    FROM students 
    WHERE snum = p_snum; 

    --if count is 0 then the student does not exist in the database, return error. 
    IF v_snum = 0 THEN 
    p_student_error := 'Student number ' || p_snum || ' is invalid. '; 
    END IF; 
END; 
/

--This procedure checks if course id is valid 
CREATE OR REPLACE PROCEDURE validate_course(
    p_callnum IN enrollments.callnum%TYPE, 
    p_course_error out VARCHAR2) AS 
    v_callnum enrollments.callnum%TYPE; 
BEGIN 
    --count the number of course with id p_callnum and assign it to v_callnum 
    SELECT count(callnum) INTO v_callnum 
    FROM schclasses 
    WHERE callnum = p_callnum; 

    --if count(callnum) = 0 then course does not exists in database, return error. 
    IF v_callnum = 0 THEN 
    p_course_error := 'Call number '|| p_callnum ||' is invalid .'; 
    END IF; 
END; 
/

--This function check the current amount of students enrolled in the course 
CREATE OR REPLACE FUNCTION course_capacity(
    p_callnum enrollments.callnum%TYPE) 
    RETURN VARCHAR2 IS 

    v_current_enrolled NUMBER(3); 
    v_capacity NUMBER(3); 
    v_capacity_error VARCHAR2(200); 
BEGIN 
    --count number of students enrolled and assign it to v_current_enrolled 
    SELECT count(snum) INTO v_current_enrolled 
    FROM enrollments 
    WHERE callnum = p_callnum 
    AND grade is null; 

    --check maximum capacity of the course and assign it to v_capacity 
    SELECT capacity INTO v_capacity 
    FROM schclasses 
    WHERE callnum = p_callnum; 

    --if current amount of students enrolled < maximum capacity then class is not full 
    --else class is full. 
    IF v_current_enrolled < v_capacity THEN 
    v_capacity_error := NULL; 
    ELSE 
    v_capacity_error := 'Course number ' || p_callnum || ' is full. '; 
    END IF; 

    RETURN v_capacity_error; 
END; 
/

--This function check the units a student currently enrolls. 
CREATE OR REPLACE FUNCTION student_unit_limit(
    p_snum students.snum%TYPE, 
    p_callnum schclasses.callnum%TYPE) 

    RETURN VARCHAR2 IS 

    v_student_crhr NUMBER(2); 
    v_course_crhr courses.crhr%TYPE; 
    v_crhr_error VARCHAR2(200); 

BEGIN 
    --count the current units the student has, and assign it to v_student_crhr 
    SELECT nvl(sum(crhr),0) INTO v_student_crhr 
    FROM courses c INNER JOIN schclasses sc ON c.dept = sc.dept 
                   AND c.cnum = sc.cnum 
         INNER JOIN enrollments e ON sc.callnum = e.callnum 
    WHERE e.snum = p_snum 
    AND grade IS NULL; 

    --find the credit hour of the course 
    SELECT crhr INTO v_course_crhr 
    FROM courses c INNER JOIN schclasses sc ON c.dept = sc.dept 
                  AND c.cnum = sc.cnum 
    WHERE sc.callnum = p_callnum; 

    --if current credit hour of student + the credit of the class <= 15 then 
    --student hasn't reached maximum allowed units and can enroll in the course. 
    IF v_student_crhr + v_course_crhr <= 15 THEN 
    v_crhr_error := NULL; 
    ELSE 
    v_crhr_error := 'Max units allowed is exceeded. '; 
    END IF; 
    RETURN v_crhr_error; 
END; 
/

--This procedure combine all 4 of procedures and functions above, 
CREATE OR REPLACE PROCEDURE addme(
    p_snum students.snum%TYPE, 
    p_callnum schclasses.callnum%TYPE) AS 

    v_error_text VARCHAR2(200); 
    v_error_msg VARCHAR2(200); 

BEGIN 
    validate_student(
    p_snum, 
    v_error_text); 

    v_error_msg := v_error_text; 

    validate_course(
    p_callnum, 
    v_error_text); 

    v_error_msg := v_error_msg || v_error_text; 

    IF v_error_msg IS NOT NULL THEN 
     dbms_output.put_line(v_error_msg); 
    ELSE 
     v_error_msg := course_capacity(p_callnum) || student_unit_limit(p_snum, p_callnum); 
     IF v_error_msg IS NOT NULL THEN 
     dbms_output.put_line(v_error_msg); 
     ELSE 
     INSERT INTO enrollments VALUES (p_snum, p_callnum, NULL); 
     COMMIT; 
     dbms_output.put_line('You have successfully enrolled in course number ' || p_callnum); 
     END IF; 
    END IF; 
END; 
/

AddMe 프로 시저가 주 프로그램이고 나머지는 서브 프로그램입니다.

+0

의 사용 가능한 복제 [응용 프로그램 오류를 올립니다 - 오라클 (https://stackoverflow.com/questions/36295233/raise-application-error-oracle) –

답변

1

나는 패키지를 만들 것을 제안합니다 :

create or replace package students_pkg as 

-- declare an exception 
student_enroll_error exception; 
-- bind error code -20001 to your custom exception 
pragma exception_init (student_enroll_error, -20001); 

-- the only visible procedure 
procedure addme(
    p_snum students.snum%type, 
    p_callnum schclasses.callnum%type); 

end students_pkg; 
/

create or replace package body students_pkg as 

procedure validate_student(
    p_snum in students.snum%type) as 

    v_snum students.snum%type; 
begin 
    -- try to find a student 
    select snum into v_snum 
    from students 
    where snum = p_snum; 

exception 
    -- if student not found, an no_data_found exception is rised 
    when no_data_found then 
    -- re-raise exception with custom code: 
    raise_application_error(-20001, 'Student number ' || p_snum || ' is invalid.'); 
end; 

-- the same logic as in the previous procedure 
procedure validate_course(p_callnum in enrollments.callnum%type) is 
    v_callnum enrollments.callnum%type; 
begin 
    select callnum into v_callnum 
    from schclasses 
    where callnum = p_callnum; 

exception 
    when no_data_found then 
    raise_application_error(-20001, 'Call number '|| p_callnum || ' is invalid .'); 
end; 

--This function check the current amount of students enrolled in the course 
procedure check_course_capacity(p_callnum enrollments.callnum%type) is 
    v_current_enrolled number(3); 
begin 
    -- here I combined queries. The idea is to make one query, which 
    -- returns one row if a course is not full and 0 rows, if it is full 
    select count(e.snum) into v_current_enrolled 
    from enrollments e 
     join schclasses s on e.callnum = s.callnum 
    where grade is null 
    group by s. capacity 
    having s. capacity > count(e.snum); 

exception 
    -- here no_data_found means that course is full 
    when no_data_found then 
    raise_application_error(-20001, 'Course number ' || p_callnum || ' is full. '); 
end; 

-- the same idea as in previous procedure, but I am not sure I fully understood the logic. 
-- You can elaborate it 
procedure check_student_unit_limit(
    p_snum students.snum%type, 
    p_callnum schclasses.callnum%type) is 

    v_course_num courses.cnum%type; 
begin 

    select c.cnum into v_student_crhr 
    from courses c inner join schclasses sc on c.dept = sc.dept and c.cnum = sc.cnum 
       inner join enrollments e on sc.callnum = e.callnum 
    where e.snum = p_snum 
    and grade is null 
    group by c.cnum 
having sum(crhr) <= 15; 

exception 
    when no_data_found then 
    raise_application_error(-20001, 'Max units allowed is exceeded. '); 
end; 

procedure addme(
    p_snum students.snum%type, 
    p_callnum schclasses.callnum%type) is 

begin 
    validate_student(p_snum); 
    validate_course(p_callnum); 
    check_course_capacity(p_callnum); 
    check_student_unit_limit(p_snum, p_callnum); 

    insert into enrollments values (p_snum, p_callnum, null); 
    -- I would not recommend you to use commit here. Call it outside this procedure 
    commit; 
    dbms_output.put_line('You have successfully enrolled in course number ' || p_callnum); 

exception 
    -- if custom exception had been raised, you will get the second parameter, 
    -- passed to raise_application_error, in SQLERRM function: 
    when student_enroll_error then 
    dbms_output.put_line(sqlerrm); 
end; 

end students_pkg; 
/
+0

안녕하세요, 라인 79 그것의 오류를 얻고있다 상태 PLS-00109 : 알 수없는 예외 이름 'STUDENT_ENROLL_ERROR'in PRAGMA EXCEPTION_INIT – Lizzie

+0

@Lizzie 죄송합니다, 제 실수. 'pragma exception_init' 표현식을 패키지 명세로 옮겨야합니다. 나는 대답에서 내 코드를 수정했다. – Dmitry

1

추가 답변 @Dmitry 할 수 있습니다. 시작과 끝 블록과 각 호출에 대한 예외 핸들로 각 프로 시저를 묶는 것이 항상 좋습니다. 따라서 예외가 발생한 곳을 정확하게 알 수 있습니다.

procedure addme(
    p_snum students.snum%type, 
    p_callnum schclasses.callnum%type) is 

    -- bind error code -20001 to your custom exception 
    pragma exception_init (student_enroll_error, -20001); 
    begin 

    Begin 
     validate_student(p_snum); 
    exception 
     --handle all the exceptions which you know of specifically 
     when no_data_found then 
      --log the error 
      dbms_output.put_line(sqlerrm); 
     --default handler 
     when other then 
      dbms_output.put_line(sqlerrm); 
    end; 

     Begin 
     validate_course(p_callnum); 
    exception 
     --handle all the exceptions which you know of specifically 
     when no_data_found then 
      --log the error 
      dbms_output.put_line(sqlerrm); 
     --default handler 
     when other then 
      dbms_output.put_line(sqlerrm); 
    end; 

     Begin 
    check_course_capacity(p_callnum); 
    exception 
     --handle all the exceptions which you know of specifically 
     when no_data_found then 
      --log the error 
      dbms_output.put_line(sqlerrm); 
     --default handler 
     when other then 
      dbms_output.put_line(sqlerrm); 
    end; 

     Begin 
    check_student_unit_limit(p_snum, p_callnum); 
    exception 
     --handle all the exceptions which you know of specifically 
     when no_data_found then 
      --log the error 
      dbms_output.put_line(sqlerrm); 
     --default handler 
     when other then 
      dbms_output.put_line(sqlerrm); 
    end; 


    insert into enrollments values (p_snum, p_callnum, null); 
    -- I would not recommend you to use commit here. Call it outside this procedure 
    commit; 
    dbms_output.put_line('You have successfully enrolled in course number ' || p_callnum); 

    exception 
    -- if custom exception had been raised, you will get the second parameter, 
    -- passed to raise_application_error, in SQLERRM function: 
    when student_enroll_error then 
     dbms_output.put_line(sqlerrm); 
    end; 
+0

응답 해 주셔서 감사합니다. 이것은 패키지의 본문 부분에 있을까요? – Lizzie

+0

예 본문입니다. –