64
Database Management 5. course

Database Management 5. course. Today Procedures Functions PL/SQL blocks Triggers

Embed Size (px)

Citation preview

Database Management

5. course

Today

• Procedures• Functions• PL/SQL blocks• Triggers

Procedures

Procedures

PROCEDURE name [(parameters)] IS

local variablesBEGIN

commands[EXCEPTION

exceptions;]END [name];

Functions

FUNCTION name [(parameters)]RETURN datatypeIS

local variablesBEGIN

commands RETURN value;[EXCEPTION

exceptions];END [name];

How to call

procedurename(parameters);

variable:=functionname(parameters);

Parameters

parametername [IN | OUT | IN OUT] datatype [{:=| DEFAULT}]• No NULL• No constraint– (id IN NUMBER(4)) -- sintax error– (id IN NUMBER) -- correct

Datatype

• Normal DB datatypes• PL/SQL datatypes

(http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/datatypes.htm)

• Table.column%TYPE• PL/SQL Variable%TYPE• Table%ROWTYPE• User-defined type:

– TYPE rectype IS RECORD(attr1 type1,…,attrn typen);– Var_name rectype;– Var_name.attr1:=value;

PL/SQL

PL/SQL block sintaxis

[DECLARE Block_var type][PROCEDURE name IS…] BEGIN name;[EXCEPTION Block_exc]END;/

PROCEDURE name [(parameters)] IS

local variablesBEGIN

commands[EXCEPTION

exceptions;]END [name];

Example

PROCEDURE emp_leaves(dnum NUMBER) ISBEGIN

DELETE FROM EMPWHERE empno = dnum;

END;BEGIN emp_leaves(7758);END;/

• dnum: formal parameter• 7758: actual parameter

SQL command

SELECT columns INTO variablesFROM table[WHERE condition];• Exactly 1 row is given back!• No. of columns=no. of variables

• Sequence• Selection• Iteration

SequenceSelection

Iteration

Selection (IF)

• IF … THEN … END IF;• IF … THEN … ELSE … END IF;• IF … THEN … [ELSIF … THEN …] ELSE … END IF;

• No. of ELSIFs is not limited

ExamplePROCEDURE size(a INTEGER) IS b VARCHAR2(40); BEGIN IF a > 999 THEN b := 'four digits or bigger'; ELSIF a > 500 THEN b:= ' bigger than 500'; ELSIF (a > 99) AND (a < 499) THEN b:= 'between 100 and 500' ; ELSIF a > 9 THEN b:= 'two digits' ; ELSE b:= 'one digit'; END IF;

...END;

Iteration (LOOP)

LOOPcommands[EXIT;][EXIT WHEN condition;]

END LOOP;

Example for LOOP

CREATE TABLE order (orderID NUMBER(4), no NUMBER(2), …);

PROCEDURE fill (var_order IN NUMBER) IS var_no NUMBER(2);BEGIN var_no :=1; LOOP INSERT INTO order (orderID, no) VALUES (var_order, var_no); var_no := var_no +1; EXIT WHEN var_no > 5; END LOOP;END;

Iteration - FOR

FOR variable IN [REVERSE] lower_bound..upper_boundLOOP

command;[command;]

END LOOP;

How it works

• variable– Initial value := lower_bound (REVERSE:

upper_bound)– Increased (REVERSE: decreased) automatically– Until reaches upper_bound (REVERSE:

lower_bound)• REVERSE: changes direction• lower_bound: lowest value of the variable• upper_bound: biggest value of the variable

Example - FOR

CREATE TABLE trial (no NUMBER(3) );

PROCEDURE insert_trial ISBEGIN FOR ind IN 1..5 LOOP INSERT INTO trial (no) VALUES (ind); END LOOP;END;

Example - FOR

PROCEDURE insert_trial (lower_bound NUMBER, upper_bound NUMBER) ISBEGINFOR ind IN lower_bound .. upper_bound LOOP INSERT INTO trial (no) VALUES (ind*2); END LOOP;END;

Iteration - WHILE

WHILE conditionLOOP

command;[command;]

END LOOP;

As long as the condition is true.

Example - WHILEPROCEDURE insert_order(param_order NUMBER, param_no NUMBER) IS

inner_no NUMBER(2):= 1;BEGIN WHILE inner_no <= param_no LOOP INSERT INTO order (orderID, no) VALUES (param_order, inner_no); inner_no := inner_no + 1; END LOOP;END;

Insert_order(123, 5); -- inserts 5 items to order no. 123

Parameter types

IN

• Only readable– Constant– Expression– Not NULL variable

Inappropriate usage

PROCEDURE owe(account IN INTEGER, amount IN INTEGER) ISmin_raise CONSTANT REAL;service CONSTANT REAL;BEGIN…IF amount<min_raise

THEN amount:=amount+service; -- errorEND IF;…END

Example for default valuesPROCEDURE new_dept

(new_dname CHAR DEFAULT ’MARKETING’, new_loc CHAR DEFAULT ’SAN FRANCISCO’) IS

BEGININSERT INTO deptVALUES(50, new_dname, new_loc);

…END;BEGINnew_dept();new_dept(’LOGISTICS’);new_dept(’LOGISTICS’,’DENVER’);END;

OUT

• Only writable– Not readable– Cannot be called with expression

Inappropriate usagePROCEDURE calculate(id IN INTEGER, premium OUT REAL) IS

hired DATE;BEGIN

SELECT sal*0.1, hiredateINTO premium, hired

FROM empWHERE empno=id;IF MONTH_BETWEEN(sysdate, hiredate)>60

THEN premium:=premium+5000; -- errorEND IF;

END;

jut_szam(111, sal+comm); -- sintax error

IN OUT

For reading and writingPROCEDURE calc(id IN INTEGER, premium IN OUT REAL) IS

hired DATE;BEGIN

SELECT sal*0.1, hiredateINTO premium, hired

FROM empWHERE empno=id;IF MONTH_BETWEEN(sysdate, hiredate)>60

THEN premium:=premium+5000;END IF;

END;

ParametersIN OUT IN OUT

Way of giving to the procedure

Not obligatory, default can be used

obligatory obligatory

How it is given to the procedure

Gives its value to the procedure

Returns with value

Gives value, returns with new value

Behavior Constant Not initialized variable

Initialized variable

Modifiable? Cannot be modified

Not readable, has to be modified

Readable, writable

What to give to the procedure

Constant, variable, expression

Just variable Just variable

Exceptions

DECLARE name_of_exc EXCEPTION;BEGIN … IF condition THEN RAISE name_of_exc;EXCEPTION WHEN name_of_exc THEN dbms_output.put_line(’Name: error.’);END;/

System exceptions

Watched by the system automatically

• NO_DATA_FOUND: select into didn’t give back any rows

• TOO_MANY_ROWS: select into gave back several rows

• OTHERS: not named exception occured

Storage in DB

• Stored as DB object

Differences

• Differences in sintaxis– AS instead of IS– CREATE has to be used– CREATE OR REPLACE PROCEDURE name…

• CREATE OR REPLACE PROCEDURE name (parameter [IN|OUT|IN OUT] type) ASBEGIN commandsEND;

• CREATE OR REPLACE FUNCTION name(parameter [IN|OUT|IN OUT] type) AS

RETURN return_type BEGIN commands END;

• DROP PROCEDURE proc_name• DROP FUNCTION func_name

Triggers

Triggers

• Automated action which is executed on DB actions– Table or view is modified– User actions– System actions

• DB object• PL/SQL, Java, or C• Transparent for the user

Trigger events

• INSERT, UPDATE, DELETE• CREATE, ALTER, DROP• Server errors• User logins, logoffs• DB startups, shut downs

What for?

• Calculate derived values• Avoid illegal/inconsistent transactions• Protection• Define referential integrities• Handle complex rules• Log• Following users• Collecting statistics• Cloning data

Trigger types

• Row-level trigger• Statement-level trigger• BEFORE and AFTER trigger• INSTEAD OF trigger• System trigger

Row-level trigger

• Run when the data of the table is modified• E.g. in case of DELETE command, the trigger is

activated for every deleted row.

Statement-level trigger

• Run once irrespectively of the number of the handled rows

• Run even if no row was modified

BEFORE and AFTER triggers

• Row or statement-level• Only for tables, not for views

INSTEAD OF trigger

• Run instead of the connected command• Only for views• Just row-level• Views are modified by triggers

System triggers

• For giving information about the DB events to the users

• They ”sign up” for the messages of the database events and other applications.– System events: DB startup, shut down,

server error– User events: login, logoff, DML/DDL commands by

the user

Sintaxis

CREATE [OR REPLACE] TRIGGER [schema.]name time event ON {DATABASE|[schema].SCHEMA} [WHEN (condition)] command• time: BEFORE | AFTER | INSTEAD OF• event:

– DDL event: for DB or schema– DB event: for DB or schema– DML event: {INSERT |DELETE | UPDATE OF [column, {…}] … ON

[schema].table | [schema].view } [REFERENCING {OLD [AS] old | NEW [AS] new | PARENT [AS] parent} … [FOR EACH ROW]

DML event

• INSERT, DELETE, UPDATE – the connected SQL command

• UPDATE OF column(s)• ON: table/schema• REFERENCING –:OLD and :NEW,

if embedded tables, PARENT has to be defined• FOR EACH ROW –row-level trigger

DDL trigger

• Run on DB or schema event– (ON {DATABASE|[schema].SCHEMA}

• E.g. ALTER, CREATE, DROP, GRANT, RENAME, REVOKE

DB event

• SERVERERROR• LOGON: of user application• LOGOFF: of user application• STARTUP• SHUTDOWN• SUSPEND: a transaction is suspended because

of server error.

Example - tablesCREATE TABLE Book (id NUMBER not null,,

ISBN VARCHAR2(30) NOT NULL,…Store NUMBER NOT NULL,Free NUMBER NOT NULL,CONSTRAINT book_pk PRIMARY KEY (id),CONSTRAINT book_free CHECK (Free >= 0))

CREATE TABLE Clients (id NUMBER not null,name VARCHAR2(100) NOT NULL,books NUMBER DEFAULT 0, Max_book NUMBER DEFAULT 10,CONSTRAINT client_pk PRIMARY KEY (id))

CREATE TABLE Borrow (Client NUMBER NOT NULL,Book NUMBER NOT NULL,Longer NUMBER DEFAULT 0,dateofloan DATE NOT NULL,… CONSTRAINT borrow_fk1 FOREIGN KEY (Client) REFERENCES Clients(Id),CONSTRAINT borrow_fk2 FOREIGN KEY (book) REFERENCES Book(Id))

CREATE TABLE Borrow_log (Book NUMBER NOT NULL,Client NUMBER NOT NULL,Dateofloan DATE NOT NULL,Dateofback DATE NOT NULL)

When borrowing a bookCREATE OR REPLACE TRIGGER tr_insert_borrowAFTER INSERT ON borrowFOR EACH ROWDECLARE var_client clients%ROWTYPE;BEGIN SELECT * INTO var_client FROM Clients WHERE id = :NEW.client; IF var_client.max_book = var_client.books THEN RAISE_APPLICATION_ERROR(-20010, var_client.name || ' cannot borrow more books.'); END IF;

When borrowing a bookINSERT INTO borrow_log(book,client,dateofloan,dateofback) VALUES (:NEW.book, :NEW.client, :NEW.dateofloan, NULL);BEGIN UPDATE book SET free = free -1 WHERE id = :NEW.book; UPDATE clients SET books = books+1 WHERE id = :NEW.client;EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20020, 'No more free copies of this book.');END;END tr_insert_borrow;

Advantages

• Automated administration of the borrows.• Inserting one row to table borrow brings in its

train the modification of tables client and book.

• Row-level, since if a book cannot be borrowed, an exception has to be given.

When book is returned

CREATE OR REPLACE TRIGGER tr_borrow_logAFTER DELETE ON borrowREFERENCING OLD AS oldborrowFOR EACH ROWBEGININSERT INTO borrow_log(book,client,dateofloan,dateofback) VALUES(:oldborrow.book, :oldborrow.client, :oldborrow.dateofloan, SYSDATE);update clients set books=books-1 where id=:oldborrow.client;update book set free=free+1 where id=:oldborrow.book;END tr_borrow_log;

Longer borrowCREATE OR REPLACE TRIGGER tr_borrow_longBEFORE INSERT OR UPDATE ON borrowFOR EACH ROWWHEN (NEW.longer > 2 OR NEW.longer < 0)BEGINRAISE_APPLICATION_ERROR(-20005,'No more prolong');END tr_borrow_long;

• After WHEN : is not needed before placeholders (OLD, NEW, PARENT)

• Check or assertion can be used also

Do not modify borrow_log

CREATE OR REPLACE TRIGGER tr_borrow_log_del_updBEFORE DELETE OR UPDATE ON borrow_logBEGINRAISE_APPLICATION_ERROR(-20100,'Permission denied.');END tr_borrow_log_del_upd;

Statement-level trigger:there is no FOR EACH ROW

Example 2

CREATE TABLE num_table(no NUMBER);CREATE OR REPLACE TRIGGER tr_doubleBEFORE INSERT ON num_tableFOR EACH ROWBEGIN :NEW.no := :NEW.no * 2;END tr_double;

INSERT INTO num_table VALUES(5);SELECT * FROM num_table;

Double the values before insertion

:NEW can be modified

CREATE OR REPLACE TRIGGER tr_book_idBEFORE UPDATE OF id ON bookFOR EACH ROWBEGINUPDATE borrow SET book = :NEW.idWHERE book = :OLD.id;END tr_book_id;

• Force integrity constraint: book in table borrow is foreign key

• Before modifying book id we modify the values in table borrow

Triggers and views

• Modify the client’s name or the book’s title through view client_book:

CREATE OR REPLACE VIEW client_book AS SELECTclients.id AS client_id, clients.name AS client,book.id AS book_id,book.title AS book FROM borrow,book,clients WHERE borrow.book=book.id AND clients.id=borrow.client;

CREATE OR REPLACE TRIGGER tr_client_book_modINSTEAD OF UPDATE ON client_bookFOR EACH ROWBEGINIF :NEW.client <> :OLD.client THEN UPDATE clients SET name = :NEW.client WHERE id = :OLD.client_id;END IF;

IF :NEW.book <> :OLD.book THEN UPDATE book SET title = :NEW.book WHERE id = :OLD.book_id;END IF;END tr_client_book_mod;

Delete a trigger

• DROP TRIGGER table.trigger

Thank you for your attention!