You are on page 1of 31

22/02/12

Object-Oriented Features in Oracle


Varying array type_ General Syntax: CREATE [OR REPLACE] TYPE <object schema> AS VARRAY(n) OF (object/data type) / CREATE OR REPLACE TYPE Persons AS VARRAY(3) OF Person_T / CREATE TABLE Course (course_id VARCHAR2(10), course_name VARCHAR2(20), lecturer Persons);
1

VARRAY
Limited collection of elements with a same type (with order)
Allow multiple nested recursions no index, can not be used in SQL (needs PL/SQL) In a type
CREATE TYPE vaddresses AS VARRAY(2) OF address

In a relational table or object-relational table


CREATE TABLE Students (num VARCHAR(15), name VARCHAR(11), adrs vadresses)

Nested table
Num. Nam. Addrese Drivers
Drivers Age

Accidents
Accident Report Photo

24

Paul

Paris

Paul Robert

45 17

134 219 037

Object Insurance
3

22/02/12

Nested table
General Syntax: CREATE [OR REPLACE] TYPE <object table schema> AS TABLE OF (object schema); / CREATE TABLE <table schema> (attribute attribute type, ...., attribute attribute type, nested item object table schema); NESTED TABLE nested item STORE AS storage table schema; CREATE TABLE <table schema> (attribute attribute type, ...., outer nested item object table schema); NESTED TABLE <outer nested item> STORE AS <outer storage table schema> (NESTED TABLE <inner nested item> STORE AS <inner storage table schema>);

Nested table- example


CREATE OR REPLACE TYPE Person_T AS OBJECT (person_id VARCHAR2(10), person_name VARCHAR2(30)) / CREATE OR REPLACE TYPE Person_Table AS TABLE OF Person_T / CREATE TABLE Course (course_id VARCHAR2(10), course_name VARCHAR2(20), lecturer Person_Table) NESTED TABLE lecturer STORE AS Person_tab;
5

Create and manipulate objectrelational tables

Propose 2 objects relational schemes for this model?


6

22/02/12

Solution
Solution 1: use reference, place Team in Player(Player reference from Team) Create type Team Create type Player (ref from Team) Create TABLE OF Team Create TABLE OF Player

Statements solution
CREATE OR REPLACE TYPE Team AS OBJECT(Name varchar(20), City varchar(20)); CREATE OR REPLACE TYPE Player AS OBJECT (LastName varchar(20), FirstName varchar(20), Salary number, Birthdate DATE, TeamRef REF Team); CREATE TABLE Teams OF Team; CREATE TABLE Players OF Player;
8

INSERT INTO Teams VALUES('Bordeaux', 'France'); INSERT INTO Teams VALUES('PUF', 'HCM'); INSERT INTO Teams VALUES('HUI', 'HCM'); INSERT INTO Teams VALUES('BAK', 'HANOI'); INSERT INTO Players SELECT 'Huong','Nguyen',1000,'3-Apr-1990',ref(t) FROM Teams t WHERE Name='Bordeaux'; INSERT INTO Players SELECT 'Tuan','Nguyen',2000,'10-Apr-1980',ref(t) FROM Teams t WHERE Name='Bordeaux'; INSERT INTO Players SELECT 'Loc','Nguyen',1500,'10-Apr-1985',ref(t) FROM Teams t WHERE Name='Bordeaux';

INSERT INTO Players SELECT 'An','Nguyen',1300,'10-Apr-1989',ref(t) FROM Teams t WHERE Name='PUF'; INSERT INTO Players SELECT 'Lam','Le',1300,'10-Apr-1995',ref(t) FROM Teams t WHERE Name='PUF';

22/02/12

Solution
Solution 2: create nested table Create type Player Table of Player Create type Team (has field Player ref type Player) Create table Team (nested Player table)

10

Statements solution
CREATE TYPE Player2 AS OBJECT (LastName varchar(20), FirstName varchar(20), Salary number, Bithday DATE); CREATE TYPE Players2 AS TABLE OF Player2; CREATE TYPE Team2 AS OBJECT (Name varchar(20), City varchar(20), Player Players2); CREATE TABLE Teams2 OF Team2 NESTED TABLE Player STORE AS TabPlayer;
11

INSERT INTO Teams2 VALUES ('Bordeaux','France',Players2(Player2('Huong','Nguyen', 1000,'1-Jan-1990'),Player2('Tuan','Anh',2000,'2-Feb1975'),Player2('Ha','Le',1500,'5-Dec-1995'))); INSERT INTO Teams2 VALUES ('PUF','HCM',Players2(Player2('Ha','Nguyen',1000,'1Jan-1990'),Player2('Phong','Le',2000,'2-Feb1975'),Player2('Ha','Le',1500,'5-Dec-1995')));

22/02/12

Discuss question
How to implement many to many association relationship using object references?

13

Solution
CREATE OR REPLACE TYPE Person_T AS OBJECT (person_id VARCHAR2(10), person_name VARCHAR2(30)) / CREATE OR REPLACE TYPE Course_T AS OBJECT (course_id VARCHAR2(10), course_name VARCHAR2(30)) / CREATE TABLE Student OF Person_T (person_id NOT NULL, PRIMARY KEY (person_id));

CREATE TABLE Course OF Course_T (course_id NOT NULL, PRIMARY KEY (course_id)); CREATE TABLE Enrolls_in (student REF Person_T, course REF Course_T);

Inheritance implementation

15

22/02/12

Inheritance implementation
General Syntax: CREATE [OR REPLACE] TYPE <super-type object schema> AS OBJECT (key attribute attribute type, attribute attribute type,..., attribute attribute type) [FINAL|NOT FINAL] / CREATE [OR REPLACE] TYPE <sub-type object schema> UNDER <super-type object schema> (additional attribute attribute type, ...., additional attribute attribute type) [FINAL|NOT FINAL] / CREATE TABLE <super-type table schema> OF <super-type object schema> (key attribute NOT NULL, PRIMARY KEY (key attribute));
16

Example
CREATE OR REPLACE TYPE Person_T AS OBJECT (id VARCHAR2(10), name VARCHAR2(20), address VARCHAR2(35)) NOT FINAL / CREATE TABLE Person OF Person_T (id NOT NULL, PRIMARY KEY (id));/ CREATE OR REPLACE TYPE Student_T UNDER Person_T (course VARCHAR2(10), year VARCHAR2(4)) / CREATE TABLE Student OF Student_T (id NOT NULL, PRIMARY KEY (id)); CREATE OR REPLACE TYPE Staff_T UNDER Person_T (department VARCHAR2(10), room_no VARCHAR2(4)) / CREATE TABLE Staff OF Staff_T (id NOT NULL, PRIMARY KEY (id));

17

ORACLE PL/SQL
Data type Declare variables Control statements Exception Procedure Function Cursor Trigger

22/02/12

PL/SQL Data Types


Built-in Simple Types:
binary_integer: -231-1 to 231-1 natural: 0 to 231 positive: 1 to 231 long: character string up to 32,760 bytes boolean: boolean type (true, false, null) number(n,m), char(n), varchar2(n) , date : same as their counterparts in SQL

%type: using an existing column type.


v_student_gpa Students.gpa%type

Define a new record type. type course_record_type is record (course_id Courses.cid%type; title Courses.title%type; credit_hours number); course_record course_record_type; %rowtype: use an existing tuple type. one_student Students%rowtype; Use . to reference record fields course_record.title = Database I;

Record Type & Row Type

Declare variables
<name_variable> <type> [[NOT NULL] := <value>]; (example : SOMENUMBER := 0;) Simple type : NUMBER CHAR VARCHAR BOOLEAN EXCEPTION TABLE.COL%TYPE

22/02/12

Control statements
IF condition THEN -- statements END IF; IF condition THEN --statements ELSE --statements END IF; IF condition THEN -- statements ELSIF condition THEN -- statements ELSIF condition THEN -- statements ELSE -- statements END IF;

LOOP
LOOP -- statements EXIT; -- statements END LOOP; LOOP -- statements EXIT WHEN condition; -- statements END LOOP;

WHILE condition LOOP --statements END LOOP; FOR i IN min .. Max LOOP --statements END LOOP; FOR i IN REVERSE max..Min LOOP --statements END LOOP;

Control structure- example


As long as the total company payroll is less than $5 million, increase employees salary by 2%. declare company_payroll number; begin select sum(salary) into company_payroll from Employees;

22/02/12

Control structure- example (cont)


while company_payroll < 5000000 loop update Employees set salary = salary * 1.02; select sum(salary) into company_payroll from Employees;

end loop;
end; /

Loops and cursors


DECLARE CURSOR C1 IS SELECT FROM WHERE ; R1 C1%ROWTYPE BEGIN LOOP R1 IN C1 -- statements END LOOP; END;

Declare cursor
To access query result one tuple at a time. CURSOR <cursor_name> IS <SQL request>; example : CURSOR c1 IS SELECT name FROM FRIENDS WHERE birthdate > 16/02/1976;
Working with a cursor:
open cursor_name; fetch cursor_name into record or variables; close cursor_name;

22/02/12

An Example of Cursors
declare cursor c1 is select cid, cname, city from customers; c1_rec c1%rowtype; begin open c1; fetch c1 into c1_rec; dbms_output.put_line(c1_rec.cid || , || c1_rec.cname || , || c1_rec.city); close c1; end; /

Cursor Attributes
begin if (not c1%isopen) then /* attribute */ open c1; end if; fetch c1 into c1_rec; while c1%found loop /* attribute */ dbms_output.put_line(c1_rec.cid || , || c1_rec.cname || , || c1_rec.city); fetch c1 into c1_rec; end loop; close c1; end; /

Cursor For Loop


begin for c1_record in c1 loop if (c1_record.city = New York) then dbms_output.put_line(c1_rec.cid || , || c1_rec.cname || , || c1_rec.city); end if; end loop; end; / open, fetch and close are done implicitly. No need to declare c1_record.

10

22/02/12

Cursor for Update


Declare a cursor for update cursor c1 is select cid, cname, city from customers for update; Use the current tuple in a cursor. update customers set city = Boston where current of c1; delete from customers where current of c1;

Cursor for Update


declare cursor c1 is select * from customers for update; begin for c1_rec in c1 loop if (c1_rec.city = New York) then delete from customers where current of c1; end if; end loop; end;

Parameterized Cursor
Declaration: cursor c1(d_name in Students.dept_name%type) is select age, avg(GPA) from Students where dept_name = d_name group by age; Usage: open c1(Computer Science);

11

22/02/12

Exceptions
An exception is any error that occurs during program execution. EXCEPTION /* exception section */ WHEN dup_val_on_index THEN dbms_output.put_line(sqlcode ||-- || sqlerrm); end; Output message if the exception occurs: -1--ORA-00001: unique constraint violated

Exceptions
Syntax: EXCEPTION WHEN exception_name THEN error-handling-code; WHEN others THEN error-handling-code; Pre-defined exceptions: invalid_cursor, too_many_rows, dup_val_on_index, no_data_found, etc.

User-Defined Exceptions
declare invalid_gpa exception; begin /* execution section */ if (gpa < 0 or gpa > 4.0) then /* Must be raised by user */ raise invalid_gpa; end if;

12

22/02/12

User-Defined Exceptions (cont.)


exception /* exception section */ when invalid_gpa then dbms_output.put_line(GPA value is invalid.); end; / It is a good practice to handle all exceptions explicitly in the exception section.
Can improve reliability and readability

Errors managements
Raise exception : RAISE <exception>; Manage exception (in a block): WHEN <exception> THEN <statement>;

Errors managements
BEGIN FOR R1 IN C1 LOOP BEGIN IF THEN RAISE nb_neg; END IF; EXCEPTION WHEN nb_neg THEN <statement>; END; END LOOP; END;

13

22/02/12

Encapsulation: Stored procedure/Function


There are three parameter: In, Out, InOut Stored-procedures general syntax:
CREATE [OR REPLACE] PROCEDURE <procedure name> [parameter [{IN | OUT | IN OUT}] parameter type, ..... parameter [{IN | OUT | IN OUT}] parameter type)] AS [local variables] BEGIN <procedure body>; END <procedure name>; GRANT EXECUTE ON <procedure_name> TO <user>;
40

Encapsulation- Example
CREATE OR REPLACE PROCEDURE Delete_Student( delete_id Student.id%TYPE) AS BEGIN DELETE FROM Student WHERE id = delete_id; END Delete_Student; / GRANT EXECUTE ON Delete_Student TO Principal;
41

Procedure
Assume a Customer relation. Write a PL/SQL program to retrieve a given customer. Report an exception if not found. set serveroutput on declare v_cid customers.cid%type; v_cname customers.cname%type; v_city customers.city%type; status boolean;

14

22/02/12

Procedure (cont.)
procedure get_customer( cust_id in customers.cid%type, cust_name out customers.cname%type, cust_city out customers.city%type, status out boolean) is begin select cname, city into cust_name, cust_city from customers where cid = cust_id; status := true; exception /* optional */ when no_data_found then status := false; end; /* procedure */

begin /* main block */ v_cid := c001; get_customer(v_cid, v_cname, v_city, status); if (status) then dbms_output.put_line(v_cid || || v_cname || || v_city); else dbms_output.put_line(Customer || v_cid || not found); end if; end; /* main block */ /

Procedure (cont.)

Functions
CREATE [OR REPLACE] FUNCTION <function name> [parameter [{IN}] parameter type, ...., parameter [{IN}] parameter type)] RETURN datatype IS [local variables] BEGIN <function body>; RETURN value; END <function name>;
45

15

22/02/12

Functions example 1
CREATE OR REPLACE FUNCTION Student_Course( s_id Student.id%TYPE) RETURN VARCHAR2 IS v_course VARCHAR(10); BEGIN SELECT course INTO v_course FROM Student WHERE id = s_id; RETURN v_course; END; /

46

Function example 2
Use a function to find the number of customers in a given city. set serveroutput on declare v_city customers.city%type; customer_no number;

Function example 2(cont.)


function no_of_customers( cust_city in customers.city%type) return number is /* must return a data */ num_of_customers number; begin select count(*) into num_of_customers from customers where city = cust_city; return (num_of_customers); end; /* function */

16

22/02/12

Function example 2 (cont.)


begin /* main block */ v_city := Dallas; customer_no := no_of_customers(v_city); dbms_output.put_line(Number of customers in || cust_city || is || customer_no); end; /* main block */ /

Example : Procedure & Function


Module 4: practice
Create three tables List of students with attributes: student code, first name, last name, years(1, 2, 3). List of courses with attributes: course code, name, coefficiency (tchi). List of notes . 1. Write a function calculating note average of a student. This function has to raise an exception if the student has no note. 2. Write a procedure which passing next year for students having average greater than 11, deleting remain students having average less than 8.

Trigger
A trigger is an event-condition-action rule coded in PL/SQL and is useful for enforcing various integrity constraints and business rules. An event is an update operation: insertion, deletion or update. The action can be a set of additional update operations or other PL/SQL statements. A trigger fires (executes the action) at a time before or after an event occurs and additional condition are satisfied.

17

22/02/12

A Sample Trigger
create or replace trigger raise_sal before update of salary on employees for each row when (new.salary > old.salary * 1.2) begin dbms_output.put_line(Old salary is || :old.salary || , || New salary is || :new.salary); dbms_output.put_line(The raise is too high!); end;

Row Trigger
Row Trigger
Fire once for each row that is affected by the event and satisfies the additional condition in the when clause. Must specify for each row.

Predefined references: new & old


new is applicable for insert and update old is applicable for update and delete use :new.salary & :old.salary in trigger body

Trigger Applications
Add a log entry each time the price of a product is changed.
The log table:

products_log (pid, username, update_date, old_price, new_price);

18

22/02/12

Trigger Application (cont.)


Create a trigger:

create or replace trigger update_p_price after update of price on products for each row begin insert into products_log values (:old.pid, user, sysdate, :old.price, :new.price); end;

Another Trigger Application


If a student is removed, delete all enrollments by the student. create or replace trigger stud_enroll after delete on students for each row begin delete from enrollments where sid = :old.sid; end;

Practice
- Create a trigger that ensures that a student can not skip class or switch to a lower class. - Create a trigger that keeps the old students. For this we will get to create a new table containing also the year of release for each student.

19

22/02/12

User-Defined Queries
User-Defined Queries in Inheritance Hierarchies
Subclass Query Superclass Query

User-Defined Queries in Association Relationships


Referencing Query Dereferencing Query

User-Defined Queries in Aggregation Hierarchies


Part Query Whole query

User-Defined Queries Using Multiple Collection Types


Varray Collection Type Nested-Table Collection Type .

User-Defined Queries with Object References


58

MEMBER PROCEDURE/FUNCTION
Member procedures and member functions are physically implemented as PL or SQL procedures or functions, and they are defined together within the specification of the object type.

MEMBER PROCEDURE/FUNCTION - SYNTAX


CREATE [OR REPLACE] TYPE <object schema> AS OBJECT (attribute attributes types, ...., attribute attributes types, MEMBER PROCEDURE <procedure name> [(parameter [{IN | OUT | IN OUT}] parameter type, ...., parameter [{IN | OUT | IN OUT}] parameter type)], MEMBER FUNCTION <function name> [(parameter [{IN}] parameter type, ...., parameter [{IN}] parameter type)] RETURN datatype); /

20

22/02/12

CREATE [OR REPLACE] TYPE BODY (object schema) AS MEMBER PROCEDURE <member procedure name> [parameter [{IN | OUT | IN OUT}] parameter type, ...., parameter [{IN | OUT | IN OUT}] parameter type)] IS [local variables] BEGIN <procedure body>; END <member procedure name>;

MEMBER FUNCTION <function name> [parameter [{IN}] parameter type, ...., parameter [{IN}] parameter type)] RETURN datatype IS [local variables] BEGIN <procedure body>; END <member function name>;

Example
Write FullName function of type Student, returning full name Write Description function of type Internship, returning text about company and subject of this internship
CREATE OR REPLACE TYPE StudentType AS OBJECT (Stu_code number,FirstName varchar(20), LastName varchar(20), MEMBER FUNCTION FullName RETURN varchar2); CREATE OR REPLACE TYPE IntershipType AS OBJECT (Company varchar(20), Subject varchar(20), StudentField REF StudentType, MEMBER FUNCTION Description RETURN varchar2 ); /

MEMBER PROCEDURE/FUNCTION EXAMPLE


---create body of function type CREATE OR REPLACE TYPE BODY StudentType AS MEMBER FUNCTION FullName RETURN varchar2 IS Results varchar(50); BEGIN SELECT (SELF.FirstName || ' '|| SELF.LastName) INTO Results FROM Dual; RETURN Results; END FullName; END; --used: SELECT s.Stu_code, s.FullName() FROM StudentType s;

21

22/02/12

MEMBER PROCEDURE/FUNCTION EXAMPLE


CREATE OR REPLACE TYPE BODY IntershipType AS MEMBER FUNCTION Description RETURN varchar2 IS Results varchar(50); BEGIN SELECT (SELF.Company||' ' || SELF.Subject) INTO Results FROM Dual; RETURN Results; END Description; END;

Practice
Write Age function of type Player, return his age. Write SumSalaries function of type Team, return sum of salaries of this team.

User-Defined Queries in Inheritance Hierarchies


Subclass Query

66

22

22/02/12

User-Defined Queries in Inheritance Hierarchies


Subclass-query representation (using shared ID) SELECT <sub-class attributes> FROM <table1, table2,,table n> WHERE <join predicates> AND <table_n.attr = &input_super-class_selection_predicates> where: Table1, , table n-1 are subclass tables, and Table_n is a superclass table.
67

Subclass-query representation (using shared ID) - Example


Find the contact number(s) of an author whose name is David Taniar. SELECT contact_no FROM Author a, Teaching_Staff b WHERE a.ao_id = b.ao_id AND a.name = David Taniar; The above query shows that we only need to join based on the common shared ID, which is ao_ID.
69

23

22/02/12

User-Defined Queries in Inheritance Hierarchies


Query representation (using treat): SELECT TREAT(VALUE(<alias>) AS <sub-type name>).<sub-class attribute> FROM <table name> WHERE <table.attr = &input_superclass_selection_predicates>;

70

Query representation (using treat)- Example


Find the institution of an author whose name is David Taniar. SELECT TREAT(VALUE(a) as Academic_T).i_name FROM Author a WHERE a.name = David Taniar;
71

Superclass- query flow

72

24

22/02/12

Superclass-query representation (using shared ID)


SELECT <super-class attributes> FROM <table1, table2, , table n> WHERE <join predicates> AND <sub-class table.attr = &input_sub-class_selection_predicates> where: Table1, , table n-1 are subclass tables, and table n is a superclass table.
73

Superclass-query example
Find the details of the author(s) whose institution name is Monash University. SELECT a.name, a.address FROM Author a, Academic b WHERE a.ao_id = b.ao_id AND b.i_name = Monash University;

74

Superclass-query example (using treat)


SELECT a.name, a.address FROM Author a WHERE TREAT(VALUE(a) as Academic).i_name = Monash University;

75

25

22/02/12

Superclass-query representation (using is of)


SELECT <super-class attribute> FROM <table name> WHERE VALUE(<alias>) IS OF (Sub-class name);

76

Superclass-query example (using is of)


Find the details of authors who belong to the industry-based type. SELECT a.name, a.address FROM Author a WHERE VALUE(a) IS OF (Industry_Based_T)

77

User-Defined Queries in Association Relationships


Referencing Query

78

26

22/02/12

Referencing-query representation
SELECT <referencing class attributes> FROM <referencing table> WHERE <referencing table path expression> [AND <class table.attr = &input_class_selection_predicates>] where: The referencing table or class is the one that holds the many side in an association relationship.
79

Dereferencing Query

80

Dereferencing-query representation
SELECT <class table attributes> FROM <referring table>, <referred table> WHERE <referencing join> [AND <class table.attr = &input_class_selection_predicates>] where: The referencing join takes the form of <referring class attribute = REF(referred class)>
81

27

22/02/12

Dereferencing-query representation
In the relationship between Course Manual and Author, display all course manuals written by John Smith. SELECT a.title FROM Course_Manual a, Author b, Publish c WHERE c.course_manual = REF(a) AND c.author = REF(b) AND b.name = John Smith;
82

Part Query
A part query is an aggregation-hierarchy query used to retrieve information of part classes, where the selection predicates are originated at the whole class.

83

Part-query representation using the nesting technique


SELECT <part class attributes> FROM THE ( SELECT whole class nested table attribute FROM <whole class table> WHERE <whole class table.attr = &input_class_selection_predicates> )

28

22/02/12

Part-query example using the nesting technique


In the relationship between Course Manual and Chapter implemented using the nesting technique, display the chapter number and chapter title of a course-manual titled Object-Relational Databases. SELECT chapter_no, chapter_title FROM THE (SELECT a.chapter FROM Course_Manual a WHERE a.title = Object-Relational Databases);

Whole Query
A whole query is the aggregation-hierarchy query to retrieve information from the whole class, where the selection predicates are originated at the part class.

Whole-query representation using the nesting technique


SELECT <whole class attributes> FROM < whole class table, TABLE(whole class nested table attribute)> WHERE <part class table.attr = &input_class_selection_predicates>

29

22/02/12

Whole-query example using the nesting technique


In the relationship between Course Manual and Chapter implemented using the nesting technique, display the course-manual ISBN and course-manual title that has an associated chapter-number 1 entitled Introduction to Object- Relational. SELECT a.isbn, a.title FROM Course_Manual a, TABLE(a.chapter) b WHERE b.c_no = 1 AND b.c_title = Introduction to Object-Relational;

User-Defined Queries Using Multiple Collection Types


Varray Collection Type: Find the details of authors whose contact numbers include 94793060. DECLARE CURSOR c_contact IS SELECT a.name, a.address, b.contact_no FROM Author a, Teaching_Staff b WHERE a.ao_id = b.ao_id; BEGIN FOR v_contactrec IN c_contact LOOP IF (v_contactrec.contact_no(1) = 94793060) OR (v_contactrec.contact_no(2) = 94793060) OR (v_contactrec.contact_no(3) = 94793060) THEN DBMS_OUTPUT.PUT_LINE(AuthorName:| | v_contactrec.name||Author Address:|| v_contactrec.address); END IF; END LOOP; END;

User-Defined Queries Using Multiple Collection Types


Nested-Table Collection Type Find the last contact number of an author whose ao_ID is 123 DECLARE Contacts Teaching_Staff.contact_no%TYPE; BEGIN SELECT b.contact_no INTO contacts FROM Author a, Teaching_Staff b WHERE a.ao_id = b.ao_id AND a.ao_id = 123; DBMS_OUTPUT.PUT_LINE (Last Contact No:|| Contacts(contacts.LAST)); END;

30

22/02/12

User-Defined Queries with Object References


Find the total number of chapters in a course manual published by an author, with ao_ID 123. DECLARE v_chapters Course_Manual.chapter%TYPE; BEGIN SELECT a.chapter INTO v_chapters FROM Course_Manual a, Author b, Publish c WHERE c.course_manual = REF(a) AND c.author = REF(b) AND b.ao_id = 123; IF v_chapters IS NOT NULL THEN DBMS_OUTPUT.PUT_LINE (The number of chapters is:||v_chapters.LAST); END IF; END;

Practice
- Create a trigger that ensures that a student can not skip class or switch to a lower class. - Create a trigger that keeps the old students. For this we will get to create a new table containing also the year of release for each student.

31

You might also like