I'm following the demo on training on classification from Oracle.
I've attached the script.
In what way can this be used to create multiple sets of rules based on a secondary column? The column wouldn't be an extra predictor, but really a way to completely isolate the rules.
That column might have its own list of data, and I'd hate to create separate sets of tables to handle the scenario.
So for example, if I added a doc_type field to ml_docs (and to the categories). When its 1 I might want to use one set of rules and if its a 2, a different set of rules. I want them to be completely isolated. What implications would that have on the script? Does Oracle support this?
create table ml_docs (
doc_id number primary key,
doc_text clob);
insert into ml_docs values
(1, 'MacTavishes is a fast-food chain specializing in burgers, fries and -
shakes. Burgers are clearly their most important line.');
insert into ml_docs values
(2, 'Burger Prince are an up-market chain of burger shops, who sell burgers -
and fries in competition with the likes of MacTavishes.');
insert into ml_docs values
(3, 'Shakes 2 Go are a new venture in the low-cost restaurant arena,
specializing in semi-liquid frozen fruit-flavored vegetable oil products.');
insert into ml_docs values
(4, 'TCP/IP network engineers generally need to know about routers,
firewalls, hosts, patch cables networking etc');
insert into ml_docs values
(5, 'Firewalls are used to protect a network from attack by remote hosts,
generally across TCP/IP');
create table ml_category_descriptions (
cd_category number,
cd_description varchar2(80));
create table ml_doc_categories (
dc_category number,
dc_doc_id number,
primary key (dc_category, dc_doc_id))
organization index;
-- descriptons for categories
insert into ml_category_descriptions values (1, 'fast food');
insert into ml_category_descriptions values (2, 'computer networking');
insert into ml_doc_categories values (1, 1);
insert into ml_doc_categories values (1, 2);
insert into ml_doc_categories values (1, 3);
insert into ml_doc_categories values (2, 4);
insert into ml_doc_categories values (2, 5);
exec ctx_ddl.create_preference('bid_lex', 'basic_lexer');
exec ctx_ddl.set_attribute ('bid_lex', 'index_themes', 'no');
exec ctx_ddl.set_attribute ('bid_lex', 'index_text', 'yes');
create index ml_docsindex on ml_docs(doc_text) indextype is ctxsys.context
parameters ('lexer bid_lex');
create table ml_rules(
rule_cat_id number,
rule_text varchar2(4000),
rule_confidence number
);
begin
ctx_cls.train(
index_name => 'ml_docsindex',
docid => 'doc_id',
cattab => 'ml_doc_categories',
catdocid => 'dc_doc_id',
catid => 'dc_category',
restab => 'ml_rules',
rescatid => 'rule_cat_id',
resquery => 'rule_text',
resconfid => 'rule_confidence'
);
end;
create index rules_idx on ml_rules (rule_text) indextype is ctxsys.ctxrule;
set serveroutput on;
declare
incoming_doc clob;
begin
incoming_doc
:= 'I have spent my entire life managing restaurants selling burgers';
for c in
( select distinct cd_description from ml_rules, ml_category_descriptions
where cd_category = rule_cat_id
and matches (rule_text, incoming_doc) > 0) loop
dbms_output.put_line('CATEGORY: '||c.cd_description);
end loop;
end;
I have movie rental database that I'm working with here and I am trying to find the most rented movie per category. I want to print out the title and the category. Here is my block of code:
declare
type listOfCat is varray(10) of varchar2(10);
categories listOfCat;
movCount number(2);
title varchar2(50);
begin
select distinct category bulk collect into categories from movie;
for i in 1.. categories.count loop
select max(count) into movCount from
(select count(r.movie_id) as count, m.title as mov, m.CATEGORY as cat from rental r
join movie m on r.movie_id = m.movie_id
where m.category = categories(i)
group by m.title, m.CATEGORY
);
dbms_output.put_line(movCount || ' ' || categories(i));
end loop;
end;
Now the problem is I don't know how to get the movie title in this case. I tried giving max(count) an alias and doing alias.mov but when adding a group by clause at the end, it gives a an invalid identifier error. Also grouping by the result I get at max(count) will just separate the result again if I have several movies per category. Finally, I also tried putting movCount, mov and cat into arrays and display them in parallel but that does not guarantee me the order would be right.
Movie table has movie_id, title, category, qty_available.
Rental table has movie_id, customer_id, due_date, returned
Customer table has customer_id, name
One way to get a max or min of one attribute and also bring along another field associated with that max or min is to use KEEP. KEEP functions to sort the data by one field, then take the record(s) with the extreme value in that attribute and resolve ties by max or min.
Here's an example with some tables that should be compatible with the query and tables you provided:
Create the test tables:
CREATE TABLE RENTAL(
MOVIE_ID NUMBER
);
CREATE TABLE MOVIE(
MOVIE_ID NUMBER,
TITLE VARCHAR2(64),
CATEGORY VARCHAR2(64)
);
And load some test data;
INSERT INTO MOVIE VALUES(1,'The Fugitive','Thriller');
INSERT INTO MOVIE VALUES(2,'No Country for Old Men','Thriller');
INSERT INTO MOVIE VALUES(3,'The Martian','Sci-Fi');
INSERT INTO MOVIE VALUES(4,'Back To The Future','Sci-Fi');
INSERT INTO MOVIE VALUES(5,'Alien','Sci-Fi');
INSERT INTO RENTAL VALUES (1);
INSERT INTO RENTAL VALUES (2);
INSERT INTO RENTAL VALUES (3);
INSERT INTO RENTAL VALUES (3);
INSERT INTO RENTAL VALUES (5);
INSERT INTO RENTAL VALUES (1);
INSERT INTO RENTAL VALUES (3);
INSERT INTO RENTAL VALUES (4);
INSERT INTO RENTAL VALUES (5);
INSERT INTO RENTAL VALUES (1);
INSERT INTO RENTAL VALUES (4);
INSERT INTO RENTAL VALUES (2);
INSERT INTO RENTAL VALUES (1);
INSERT INTO RENTAL VALUES (3);
INSERT INTO RENTAL VALUES (2);
INSERT INTO RENTAL VALUES (2);
Now if we query to get some initial expectation for the pl/sql block, we can see we have a tie in the Thriller category:
SELECT MOVIE.TITLE, MOVIE.CATEGORY, COUNT(*) AS RENTAL_COUNT FROM MOVIE
INNER JOIN RENTAL
ON MOVIE.MOVIE_ID = RENTAL.MOVIE_ID
GROUP BY MOVIE.TITLE, MOVIE.CATEGORY
ORDER BY 2 ASC, 3 DESC;
TITLE CATEGORY RENTAL_COUNT
The Martian Sci-Fi 4
Alien Sci-Fi 2
Back To The Future Sci-Fi 2
No Country for Old Men Thriller 4
The Fugitive Thriller 4
So we should end up with The Martian in Sci-Fi, but we'll need to resolve that tie in Thriller with KEEP.
Now run the pl/sql block. I modified the query and added the movie title to the printed statement here but it is largely the same. max-count gets the higest number of rentals, and KEEP gets the movie with that number of rentals.
declare
type listOfCat is varray(10) of varchar2(10);
categories listOfCat;
movCount number(2);
movieTitle varchar2(50);
begin
select distinct category bulk collect into categories from movie;
for i in 1.. categories.count loop
SELECT MIN(TITLE) KEEP (DENSE_RANK FIRST ORDER BY COUNT(*) DESC),
MAX(COUNT(*))
INTO movieTitle, movCount
FROM MOVIE
INNER JOIN RENTAL
ON MOVIE.MOVIE_ID = RENTAL.MOVIE_ID
WHERE MOVIE.CATEGORY = categories(i)
GROUP BY MOVIE.TITLE;
dbms_output.put_line(utl_lms.format_message('Category: %s, Most-Rented-Movie:%s, Rental-Count:%s',categories(i),movieTitle,to_char(movCount)));
end loop;
end;
/
Result:
Category: Sci-Fi, Most-Rented-Movie:The Martian, Rental-Count:4
Category: Thriller, Most-Rented-Movie:No Country for Old Men, Rental-Count:4
In this case, MIN(TITLE) resolved the tie between The Fugitive and No Country for Old Men.
I've two table in the database, the first one is Person and the second is Pilot. as following:
Person Table:
CREATE TABLE person(
person_id NUMBER PRIMARY KEY,
last_name VARCHAR2(30) NOT NULL,
first_name VARCHAR2(30) NOT NULL,
hire_date VARCHAR2(30) NOT NULL,
job_type CHAR NOT NULL,
job_status CHAR NOT NULL
);
/
INSERT INTO person VALUES (1000, 'Smith', 'Ryan', '04-MAY-90','F', 'I');
INSERT INTO person VALUES (1170, 'Brown', 'Dean', '01-DEC-92','P', 'A');
INSERT INTO person VALUES (2010, 'Fisher', 'Jane', '12-FEB-95','F', 'I');
INSERT INTO person VALUES (2080, 'Brewster', 'Andre', '28-JUL-98', 'F', 'A');
INSERT INTO person VALUES (3190, 'Clark', 'Dan', '04-APR-01','P', 'A');
INSERT INTO person VALUES (3500, 'Jackson', 'Tyler', '01-NOV-05', 'F', 'A');
INSERT INTO person VALUES (4000, 'Miller', 'Mary', '11-JAN-08', 'F', 'A');
INSERT INTO person VALUES (4100, 'Jackson', 'Peter', '08-AUG-11', 'P','I');
INSERT INTO person VALUES (4200, 'Smith', 'Ryan', '08-DEC-12', 'F','A');
COMMIT;
/
Pilot Table:
CREATE TABLE pilot(
person_id NUMBER PRIMARY KEY,
pilot_type VARCHAR2(100) NOT NULL,
CONSTRAINT fk_person_pilot FOREIGN KEY (person_id)
REFERENCES person(person_id)
);
/
INSERT INTO pilot VALUES (1170, 'Commercial pilot');
INSERT INTO pilot VALUES (2010, 'Airline transport pilot');
INSERT INTO pilot VALUES (3500, 'Airline transport pilot');
COMMIT;
/
I'm asked to write a pl/sql block of code that accepts the last name from the user and return the result as following:
1) if the last name is not in the table, it returns all the rows in the table.
2) if the last name is in the table, it shows all of the employee's information.
So far I'm doing well with the code, but I got stuck in the case that there are two employees with the last name. here is the cursor that I wrote:
cursor person_info is
select last_name, first_name, hire_date, job_type, job_status, nvl(pilot_type, '-----------')
from person
full outer join pilot
on person.person_id = pilot.person_id
where upper(last_name) = upper(v_last_name)
group by last_name, first_name, hire_date, job_type, job_status, pilot_type
order by last_name, first_name, hire_date asc;
Logically, there are three cases to be covered:
the first case, when the entered last name is in the table, I return all the rows in the table and that's done.
The second case when there is only one employee with the entered last name, and this case is done as well. The last case when there are more than one employee having the same last name like for example 'Jackson' or 'Smith' in this case, my program crashes and give me the error that my select into statement returns more than one row.
select person_id
into v_n
from person
where upper(last_name) = upper(v_last_name);
if v_n = 1 then
open person_info;
fetch person_info into v_last_name, v_first_name, v_hire_date, v_job_type, v_job_status, v_pilot_type;
Can someone help me in guiding me how to fetch the data correctly? I'm not allowed to create any temporary tables or views.
I'm so sorry for making the problem longer than it should, but I was trying to be as clear as possible in explaining the problem.
Thank you in advance.
if the error is
"ORA-01422 exact fetch returns more than requested number of rows" then I think your answer is here https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:981494932508
If you EXPECT the query to return more than one row, you would code:
for x in ( select * from t where ... )
loop
-- process the X record here
end loop;
Your immediate issue is that you're selecting the matching person_id into a variable, and then seeing if that specific ID is 1. You don't have an actual ID 1 anyway so that check would never match; but it is that querying matching multiple rows that gets the error, as you can't put two matching IDs into a single scalar variable.
The way you've structured it looks like you are trying to count how many matching rows there are, rather than looking for a specific ID:
select count(person_id)
into v_n
from person
where upper(last_name) = upper(v_last_name);
if v_n = 1 then
....
When you do have multiple matches then you will need to use the same mechanism to return all of those as you do when there are no matches and you return all employees. You may find the logic should be in the cursor query rather then in PL/SQL logic. It depends on the details of the assignment though, and how it expects you to return the data in both (or all three) scenarios.
It's also possible you just aren't expected to hit this problem - it isn't clear if the assignment is finding all employees, or only those that are pilots. The issue still exists in general, but with the data you show there aren't any duplicate pilot last names. If you haven't learned about this kind of error yet perhaps you're getting a bit ahead of what your tutor expects.
I want to automate the registrations system so that it automatically registers students. Then I want a procedure to automate the grading system. I have included the code that I am written to make most of this assignment work which it does but unsure how to incorporate PL\SQL automated functions for the registrations system, and the grading system. So any help or ideas I would greatly appreciated please.
set Linesize 250
set pagesize 150
drop table student;
drop table faculty;
drop table Course;
drop table Section;
drop table location;
DROP TABLE courseInstructor;
DROP TABLE Registration;
DROP TABLE grade;
create table student(
studentid number(10),
Lastname varchar2(20),
Firstname Varchar2(20),
MI Char(1),
address Varchar2(20),
city Varchar2(20),
state Char(2),
zip Varchar2(10),
HomePhone Varchar2(10),
Workphone Varchar2(10),
DOB Date,
Pin VARCHAR2(10),
Status Char(1));
ALTER TABLE Student
Add Constraint Student_StudentID_pk Primary Key (studentID);
Insert into student values (1,'xxxxxxxx','xxxxxxxxxx','x','xxxxxxxxxxxxxxx','Columbus','oh','44159','xxx-xxx-xxxx','xxx-xxx-xxxx','06-Mar-1957','1211','c');
create table faculty(
FacultyID Number(10),
FirstName Varchar2(20),
Lastname Varchar2(20),
MI Char(1),
workphone Varchar2(10),
CellPhone Varchar2(10),
Rank Varchar2(20),
Experience Varchar2(10),
Status Char(1));
ALTER TABLE Faculty
ADD Constraint Faculty_facultyId_PK PRIMARY KEY (FacultyID);
insert into faculty values (1,'xxx','xxxxxxxxxxxx','xxx-xxx-xxxx','xxx-xxx-xxxx','professor','20','f');
create table Course(
CourseId number(10),
CourseNumber Varchar2(20),
CourseName Varchar(20),
Description Varchar(20),
CreditHours Number(4),
Status Char(1));
ALTER TABLE Course
ADD Constraint Course_CourseID_pk PRIMARY KEY(CourseID);
insert into course values (1,'cit 100','computer concepts','introduction to PCs','3.0','o');
insert into course values (2,'cit 101','Database Program','Database Programming','4.0','o');
insert into course values (3,'Math 101','Algebra I','Algebra I Concepts','5.0','o');
insert into course values (4,'cit 102a','Pc applications','Aplications 1','3.0','o');
insert into course values (5,'cit 102b','pc applications','applications 2','3.0','o');
insert into course values (6,'cit 102c','pc applications','applications 3','3.0','o');
insert into course values (7,'cit 103','computer concepts','introduction systems','3.0','c');
insert into course values (8,'cit 110','Unified language','UML design','3.0','o');
insert into course values (9,'cit 165','cobol','cobol programming','3.0','o');
insert into course values (10,'cit 167','C++ Programming 1','c++ programming','4.0','o');
insert into course values (11,'cit 231','Expert Excel','spreadsheet apps','3.0','o');
insert into course values (12,'cit 233','expert Access','database devel.','3.0','o');
insert into course values (13,'cit 169','Java Programming I','Java Programming I','3.0','o');
insert into course values (14,'cit 263','Visual Basic','Visual Basic Prog','3.0','o');
insert into course values (15,'cit 275','system analysis 2','System Analysis 2','3.0','o');
create table Section(
SectionID Number(10),
CourseId Number(10),
SectionNumber VarChar2(10),
Days Varchar2(10),
StartTime Date,
EndTime Date,
LocationID Number(10),
SeatAvailable Number(3),
Status Char(1));
ALTER TABLE Section
ADD Constraint Section_SectionID_PK PRIMARY KEY(SectionID);
insert into section values (1,1,'18977','r','21-Sep-2011','10-Dec-2011','1','89','o');
create table Location(
LocationId Number(10),
Building Varchar2(20),
Room Varchar2(5),
Capacity Number(5),
Satus Char(1));
ALTER TABLE Location
ADD Constraint Location_LocationID_pk PRIMARY KEY (LocationID);
insert into Location values (1,'Clevleand Hall','cl209','35','o');
insert into Location values (2,'Toledo Circle','tc211','45','o');
insert into Location values (3,'Akron Square','as154','65','o');
insert into Location values (4,'Cincy Hall','ch100','45','o');
insert into Location values (5,'Springfield Dome','SD','35','o');
insert into Location values (6,'Dayton Dorm','dd225','25','o');
insert into Location values (7,'Columbus Hall','CB354','15','o');
insert into Location values (8,'Cleveland Hall','cl204','85','o');
insert into Location values (9,'Toledo Circle','tc103','75','o');
insert into Location values (10,'Akron Square','as201','46','o');
insert into Location values (11,'Cincy Hall','ch301','73','o');
insert into Location values (12,'Dayton Dorm','dd245','57','o');
insert into Location values (13,'Springfield Dome','SD','65','o');
insert into Location values (14,'Cleveland Hall','cl241','10','o');
insert into Location values (15,'Toledo Circle','tc211','27','o');
insert into Location values (16,'Akron Square','as311','28','o');
insert into Location values (17,'Cincy Hall','ch415','73','o');
insert into Location values (18,'Toledo Circle','tc111','67','o');
insert into Location values (19,'Springfield Dome','SD','69','o');
insert into Location values (20,'Dayton Dorm','dd211','45','o');
Alter Table Student
Add Constraint student_Zip_CK Check(Rtrim (Zip,'1234567890-') is null);
Alter Table Student
ADD Constraint Student_Status_CK Check(Status In('c','t'));
Alter Table Student
ADD Constraint Student_MI_CK2 Check(RTRIM(MI,'abcdefghijklmnopqrstuvwxyz')is Null);
Alter Table Student
Modify pin not Null;
Alter table Faculty
Add Constraint Faculty_Status_CK Check(Status In('f','a','i'));
Alter table Faculty
ADD Constraint Faculty_Rank_CK Check(Rank In ('professor','doctor','instructor','assistant','tenure'));
Alter table Faculty
ADD Constraint Faculty_MI_CK2 Check(RTRIM(MI,'abcdefghijklmnopqrstuvwxyz')is Null);
Update Section Set Starttime = To_date('09-21-2011 6:00 PM', 'mm-dd-yyyy hh:mi pm');
Update Section Set Endtime = To_date('12-10-2011 9:50 PM', 'mm-dd-yyyy hh:mi pm');
alter table Section
Add Constraint StartTime_Status_CK Check (starttime < Endtime);
Alter Table Section
Add Constraint Section_StartTime_ck check (StartTime < EndTime);
Alter Table Section
ADD Constraint Section_CourseId_FK FOREIGN KEY (CourseID) References Course(CourseId);
Alter Table Section
ADD Constraint Section_LocationID_FK FOREIGN KEY (LocationID) References Location (LocationId);
Alter Table Section
ADD Constraint Section_Days_CK Check(RTRIM(Days,'mtwrfsu')IS Null);
update section set seatavailable = '99';
Alter Table Section
ADD Constraint Section_SeatsAvailable_CK Check (SeatAvailable < 100);
Alter Table Course
Add Constraint Course_CreditHours_ck check(CreditHours < = 6.0);
update location set capacity = '99';
Alter Table Location
Add Constraint Location_Capacity_CK Check(Capacity < 100);
Create Table Registration (
StudentID Number(10),
SectionID Number(10),
Constraint Registration_pk Primary key (studentId, Sectionid));
Insert into registration values (1, 2);
Insert into Registration values (2, 3);
Insert into registration values (3, 4);
Insert into registration values (4, 5);
Insert into registration values (5, 6);
Insert into registration values (6, 7);
Insert into registration values (7, 8);
Insert into registration values (8, 9);
insert into registration values (9, 10);
insert into registration values (10, 11);
insert into registration values (9, 12);
insert into registration values (8, 13);
insert into registration values (7, 14);
insert into registration values (6, 15);
insert into registration values (5, 17);
insert into registration values (4, 18);
insert into registration values (3, 19);
insert into registration values (2, 20);
insert into registration values (1, 21);
insert into registration values (2, 22);
insert into registration values (3, 23);
insert into registration values (4, 24);
insert into registration values (5, 25);
Insert into registration values (6, 24);
insert into registration values (7, 23);
insert into registration values (8, 22);
insert into registration values (9, 21);
insert into registration values (10, 20);
insert into registration values (9, 19);
insert into registration values (8, 17);
Create Table courseInstructor(
FacultyID Number(10),
SectionID Number(10),
Constraint CourseInstructor_pk Primary key (FacultyId, SectionID));
insert into courseInstructor values (1, 1);
insert into courseInstructor values (2, 2);
insert into courseInstructor values (3, 3);
insert into courseInstructor values (4, 4);
insert into courseInstructor values (5, 5);
insert into courseInstructor values (5, 6);
insert into courseInstructor values (4, 7);
insert into courseInstructor values (3, 8);
insert into courseInstructor values (2, 9);
insert into courseInstructor values (1, 10);
insert into courseInstructor values (5, 11);
insert into courseInstructor values (4, 12);
insert into courseInstructor values (3, 13);
insert into courseInstructor values (2, 14);
insert into courseInstructor values (1, 15);
Create table grade(
StudentID Number(10),
SectionID Number(10),
Grade Varchar2(1),
Constraint grade_pk Primary key (StudentID, SectionID));
CREATE OR REPLACE TRIGGER TR_CreateGrade
AFTER INSERT ON Registration
FOR EACH ROW
BEGIN
INSERT INTO grade (SectionID,StudentID,Grade)
VALUES(:New.SectionID,:New.StudentID,NULL);
END TR_createGrade;
/
CREATE OR REPLACE FORCE VIEW V_reg_student_course AS
SELECT
Registration.StudentID,
student.LastName,
student.FirstName,
course.CourseName,
Registration.SectionID,
course.CreditHours,
section.Days,
TO_CHAR(StartTime, 'MM/DD/YYYY') AS StartDate,
TO_CHAR(StartTime, 'HH:MI PM') AS StartTime,
TO_CHAR(EndTime, 'MM/DD/YYYY') AS EndDate,
TO_CHAR(EndTime, 'HH:MI PM') AS EndTime,
location.Building,
location.Room
FROM registration, student, section, course, location
WHERE registration.StudentID = student.StudentID
AND registration.SectionID = section.SectionID
AND section.LocationID = location.LocationID
AND section.CourseID = course.CourseID;
CREATE OR REPLACE FORCE VIEW V_teacher_to_course AS
SELECT
courseInstructor.FacultyID,
faculty.FirstName,
faculty.LastName,
courseInstructor.SectionID,
section.Days,
TO_CHAR(StartTime, 'MM/DD/YYYY') AS StartDate,
TO_CHAR(StartTime, 'HH:MI PM') AS StartTime,
TO_CHAR(EndTime, 'MM/DD/YYYY') AS EndDate,
TO_CHAR(EndTime, 'HH:MI PM') AS EndTime,
location.Building,
location.Room
FROM courseInstructor, faculty, section, course, location
WHERE courseInstructor.FacultyID = faculty.FacultyID
AND courseInstructor.SectionID = section.SectionID
AND section.LocationID = location.LocationID
AND section.CourseID = course.CourseID;
SELECT * FROM V_reg_student_course;
SELECT * FROM V_teacher_to_course;
I do not know how much detail is required for this exercise but these are the things I see:
You are mixing CHAR and VARCHAR2 types, there is no reason to do this. Make your life easier and stick with VARCHAR2 if the entries are expected to be less than 4000 characters
Many people's names, cities and addresses are much longer than 20 characters. Think big, 250 characters.
Middle Initial is problematic. Not everyone has one and if they do they may want their full middle name spelled out.
Address information should be broken out into a series of separate tables but I grant this may be beyond the scope of your assignment
Not everyone lives in the United States, think about a numeric key to a secondary table for cities and states/provinces.
Many of these fields should be not null such as course number, course name
Now, onto your question about automating functions. I am not sure what you really want. A student registering for a course is initiated outside of the database. Staff would enter the students registration choices based on a form. Or the student would submit them electronically, either way some front-end application would initiate the transaction.
For example, on your front end, someone presses "Submit". Then the old fashioned way is to open a connection to the database, add some parameters, make a procedure call like
Add_student_to_course(student_id_in IN NUMBER, section_id_in IN NUMBER, registration_out OUT sys_refcursor)
Inside the procedure you check to see whether the student exists, course exists, course has seats available.
There are many different ways of dealing with error handling depending on the complexity of the validation process. If it is possible for one registration to violate several business rules then you want to return complex information. (if the course must have a seat available, if the course must have a teacher, if the student is paid up).
So, do your processing as if statements. When everything is fine, in a simple application, the sys_refcursor could look like
select registration_no, error_number from dual;
If everything is fine error_number is 0, if not return an error code. Otherwise the registration code is 0 and the error code refers to a table of errors with a human readable text.
(I am aware that this is a simplistic approach but this is a simplified exercise)