Upload
nicholas-ellis
View
218
Download
0
Embed Size (px)
Citation preview
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];
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 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
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;
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;
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
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;
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
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;
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
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;