ITM-661 ระบบฐานข้อมูล (Database system). Walailak - 2013. •. T. Connolly, and C.
Begg, “Database Systems: A Practical Approach to Design, Implementation, and
... R. Elmasri and S. B. Navathe, “Fundamentals of Database Systems”, 5th ed., ...
ITM-661 ระบบฐานข้อมูล (Database system)
Walailak - 2013
Lecture 7 Stored procedure Walailak University • • •
T. Connolly, and C. Begg, “Database Systems: A Practical Approach to Design, Implementation, and Management”, 5th edition, Addison-Wesley, 2010. ISBN: 0-321-60110-6, ISBN-13: 978-0-321-60110-0 (International Edition). T. Connolly, and C. Begg, “Database Systems: A Practical Approach to Design, Implementation, and Management”, 4th edition, Addison-Wesley, 2004. ISBN: 0-321-21025-5. R. Elmasri and S. B. Navathe, “Fundamentals of Database Systems”, 5th ed., Pearson, 2007, ISBN: 0-321-41506-X.
Objectives To
study what a stored procedure is To study what a stored function is To study how to use a stored procedure To study how to use a stored function To study how to use a cursor To study how to use a trigger See detail at http://dev.mysql.com/doc/refman/5.0/en/
Stored Procedure/Function
A stored procedure is a set of SQL statements that can be stored in the server. Stored routines (procedures and functions) are normally supported in several DBMSs, including Oracle, Postgres, MySQL, DB2 and so on. Stored routines can provide improved performance because less information needs to be sent between the server and the client. Once this has been done, clients do not need to keep reissuing the individual statements but can refer to the stored procedure instead.
Stored Procedure/Function
The tradeoff is that this does increase the load on the database server because more of the work is done on the server side and less is done on the client (application) side.
e.g., many client machines (such as Web servers) are serviced by only one or a few database servers.
Stored routines also allow you to have libraries of functions in the database server. (e.g, classes). Using these client application language features is beneficial for the programmer even outside the scope of database use.
PL/SQL PL/SQL is Oracle's procedural language extension to SQL. PL/SQL combines SQL with the procedural functionality of a structured programming language, such as IF ... THEN, WHILE, and LOOP. The PL/SQL engine used to define, compile, and execute PL/SQL program units. A component of many Oracle products, including Oracle Server.
MySQL Stored Routines: Overview The routines are stored on server They belong to database They are based on standard SQL specification Three main components are
Procedure
Function Trigger
MySQL Stored Procedures: Overview
Parameter type IN OUT INOUT
The procedures may return one or more data sets as OUT parameters It is possible to use dynamic SQL
MySQL Stored Functions: Overview The MySQL function has only input PARAMETERS It MUST return one value of a given type It cannot be used with dynamic SQL It cannot return data sets
MySQL Triggers: Overview A trigger is associated to table events (INSERT, UPDATE,DELETE) Its parameters depend on the event It does not return anything It is not possible to use it with dynamic SQL It cannot return data sets
How to write a stored routine? CREATE PROCEDURE CREATE FUNCTION BEGIN .. END blocks IF ... THEN ... ELSE ... END IF CASE ... THEN ... THEN ... ELSE ... END CASE WHILE ... END WHILE LOOP ... END LOOP DECLARE HANDLERS CURSORS
An Example of Procedure mysql> delimiter // mysql> -> -> -> -> -> -> -> mysql> mysql> mysql> mysql>
CREATE PROCEDURE odd_or_even (IN x INT) BEGIN IF (x mod 2 = 0) THEN SELECT CONCAT(x, " is even") as answer; ELSE SELECT CONCAT(x, " is odd") as answer; END IF; mysql> call odd_or_even(20); END// +------------+ delimiter ; | answer | +------------+ call odd_or_even(20); | 20 is even | call odd_or_even(7); +------------+ 1 row in set (0.00 sec) mysql> call odd_or_even(7); +------------+ | answer | +------------+ | 7 is odd | +------------+ 1 row in set (0.00 sec)
Another Example of Procedure mysql> delimiter // mysql> CREATE PROCEDURE simpleproc (OUT param1 INT) -> BEGIN -> SELECT COUNT(*) INTO param1 FROM Branch; -> END; -> // Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; mysql> CALL simpleproc(@a); Query OK, 0 rows affected (0.00 sec) mysql> DROP PROCEDURE simpleproc; mysql> SELECT @a; +------+ | @a | +------+ | 3 | +------+ 1 row in set (0.00 sec)
Another Example of Procedure DROP PROCEDURE simpleproc1; delimiter //
CREATE PROCEDURE simpleproc1 (IN tabname VARCHAR(20)) BEGIN SET @s = CONCAT('SELECT COUNT(*) into @a FROM ',tabname); PREPARE z FROM @s; EXECUTE z; END; // mysql> SELECT @a; +------+ delimiter ; | @a | CALL simpleproc1('branch'); +------+ | 3 | +------+ 1 row in set (0.00 sec)
An Example of Function delimiter // CREATE FUNCTION less_than_five (x INT) RETURNS CHAR(3) BEGIN IF (x < 5) THEN mysql> SELECT less_than_five(4); RETURN 'YES'; +---------------------+ ELSE | less_than_five(5) | +---------------------+ RETURN 'NO'; | YES | END IF; +---------------------+ END// 1 row in set (0.00 sec) delimiter ; mysql> SELECT less_than_five(8); SELECT less_than_five(4); DROP FUNCTION less_than_five; +---------------------+ | less_than_five(8) | +---------------------+ | NO | +---------------------+ 1 row in set (0.00 sec)
Another Example of Function CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50) RETURN CONCAT('Hello, ',s,'!'); Query OK, 0 rows affected (0.00 sec) mysql> SELECT hello('world'); +----------------+ | hello('world') | +----------------+ | Hello, world! | +----------------+ 1 row in set (0.00 sec) mysql> DROP FUNCTION hello;
An Example Database (for Cursor) mysql> use test
CREATE TABLE data1 ( id integer PRIMARY KEY, data decimal(4,2) ); CREATE TABLE data2 ( id integer PRIMARY KEY, data decimal(4,2) ); CREATE TABLE data3 ( id integer PRIMARY KEY, data decimal(4,2) ); LOAD DATA LOCAL INFILE 'data1.txt' INTO TABLE data1; LOAD DATA LOCAL INFILE 'data2.txt' INTO TABLE data2;
The First Example of Cursor delimiter // CREATE PROCEDURE curdemo() BEGIN DECLARE done INT DEFAULT 0; DECLARE a CHAR(16); DECLARE b,c DECIMAL(4,2); DECLARE cur1 CURSOR FOR SELECT id, data FROM data1; DECLARE cur2 CURSOR FOR SELECT data FROM data2; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; OPEN cur2; REPEAT FETCH cur1 INTO a, b; FETCH cur2 INTO c; IF NOT done THEN IF b < c THEN INSERT INTO data3 VALUES (a,b); ELSE INSERT INTO data3 VALUES (a,c); END IF; END IF; UNTIL done END REPEAT;
CLOSE cur1; CLOSE cur2; END// delimiter ;
The Second Example of Cursor (I) DROP table salary; DROP table bonustable; CREATE TABLE salary ( staffid VARCHAR(5) salary DECIMAL(6,2) work_done INTEGER bonus INTEGER ); CREATE TABLE bonustable ( bonus INTEGER ); insert into salary values insert into salary values insert into salary values
PRIMARY KEY, NOT NULL, NOT NULL,
('s0001', 100.0, 4, 100); ('s0002', 200.0, 6, 200); ('s0003', 400.0, 12, 300);
The Second Example of Cursor (II) DROP PROCEDURE cpbonus; delimiter // CREATE PROCEDURE cpbonus() BEGIN DECLARE done BOOLEAN DEFAULT FALSE; DECLARE my_bonus INT; DECLARE get_it CURSOR FOR SELECT bonus FROM salary; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=TRUE; OPEN get_it; GETTING: LOOP FETCH get_it INTO my_bonus; IF done THEN LEAVE GETTING; END IF; INSERT INTO bonustable values (my_bonus); END LOOP; END// delimiter ; call cpbonus(); select * from bonustable;
Trigger – the first example
DROP table salary; CREATE TABLE salary ( staffid VARCHAR(5) PRIMARY KEY, salary DECIMAL(6,2) NOT NULL, work_done INTEGER NOT NULL, bonus INTEGER ); delimiter // CREATE TRIGGER salary_bi BEFORE INSERT ON salary FOR EACH ROW BEGIN CASE WHEN new.work_done > 10 THEN SET new.bonus = 5000; WHEN new.work_done > 5 THEN SET new.bonus = 2500; WHEN new.work_done > 2 THEN SET new.bonus = 1000; ELSE SET new.bonus = 0; END CASE; END// delimiter ; insert into salary (staffid,salary,work_done) values ('s0001', 100.0, 4); insert into salary (staffid,salary,work_done) values ('s0002', 200.0, 6); insert into salary (staffid,salary,work_done) values ('s0003', 400.0, 12);
Trigger – the second example DROP table salary; CREATE TABLE salary ( staffid VARCHAR(5) PRIMARY KEY, salary DECIMAL(6,2) NOT NULL, work_done INTEGER NOT NULL, bonus INTEGER ); delimiter // CREATE TRIGGER salary_update BEFORE UPDATE ON salary FOR EACH ROW BEGIN IF old.salary > new.salary THEN SET new.salary = 2000; END IF; END// delimiter ; insert into salary (staffid,salary,work_done) values ('s0001', 100.0, 4); insert into salary (staffid,salary,work_done) values ('s0002', 200.0, 6); insert into salary (staffid,salary,work_done) values ('s0003', 400.0, 12);
Trigger – the second example CREATE TABLE test1(a1 INT); CREATE TABLE test2(a2 INT); CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY); CREATE TABLE test4( a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b4 INT DEFAULT 0 ); DELIMITER | CREATE TRIGGER testref BEFORE INSERT ON test1 FOR EACH ROW BEGIN INSERT INTO test2 SET a2 = NEW.a1; DELETE FROM test3 WHERE a3 = NEW.a1; UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1; END; | DELIMITER ; INSERT INTO test3 (a3) VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL); INSERT INTO test4 (b4) VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);
Trigger (II) mysql> INSERT INTO test1 VALUES -> (1), (3), (1), (7), (1), (8), (4), (4); Query OK, 8 rows affected (0.01 sec) mysql> SELECT * FROM test1; +------+ | a1 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec)
mysql> SELECT * FROM test2; +------+ | a2 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec)
Trigger (III) mysql> SELECT * FROM test2; +------+ | a2 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec)
mysql> SELECT * FROM test3; +----+ | a3 | +----+ | 2 | | 5 | | 6 | | 9 | | 10 | +----+ 5 rows in set (0.00 sec)
Trigger (IV) mysql> SELECT * FROM test1; +------+ | a1 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec)
mysql> SELECT * FROM test4; +----+------+ | a4 | b4 | +----+------+ | 1 | 3 | | 2 | 0 | | 3 | 1 | | 4 | 2 | | 5 | 0 | | 6 | 0 | | 7 | 1 | | 8 | 1 | | 9 | 0 | | 10 | 0 | +----+------+ 10 rows in set (0.00 sec)
Information_schema (I) mysql> use information_schema; mysql> show tables;
Information_schema (II) mysql> select routine_name, routine_type mysql> from routines;
Information Schema = Metadata