mysql stored procedure and user-defined function isys 475
TRANSCRIPT
MySQL Stored Procedure and User-Defined Function
http://www.mysqltutorial.org/
ISYS 475
Stored Procedure
• A stored procedure is a program with SQL code which is stored in the database catalog and can be invoked later by a program, a trigger or even a stored procedure.
• MySQL supports stored procedure since version 5.0 to allow MySQL more flexible and powerful.
Three Ways to Create A Procedure
• 1. Save the procedure commands in a text file.
• 2. Use the phpMyAdmin utility to enter commands– Routine/Add routine
• 3. Enter the commands using the MySQL command prompt.
Example of a command fileDELIMITER // CREATE PROCEDURE Hello() LANGUAGE SQL DETERMINISTIC SQL SECURITY DEFINER COMMENT 'A procedure' BEGIN SELECT 'Hello World !'; END//
phpMyAdmin: Routines/Add routine interface
Optional characteristics
• Type: Procedure/Function• Language :the default value is SQL.• Deterministic : If the procedure always returns the
same results, given the same input. The default value is NOT DETERMINISTIC.
• SQL Security : At call time, check privileges of the user. INVOKER is the user who calls the procedure. DEFINER is the creator of the procedure. The default value is DEFINER.
• Comment : For documentation purposes; the default value is ""
Run a procedure
• With phpMyAdmin:– Routines/select the procedure and click execute
• With the command prompt:CALL stored_procedure_name (param1, param2, ....);
CREATE PROCEDURE ProcName()
• Stored procedure names are case insensitive
• A procedure may have parameters
Define parameters within a stored procedure• Parameter list is empty
– CREATE PROCEDURE proc1 () :
• Define input parameter with key word IN:– CREATE PROCEDURE proc1 (IN varname DATA-
TYPE)
– The word IN is optional because parameters are IN (input) by default.
• Define output parameter with OUT:– CREATE PROCEDURE proc1 (OUT varname DATA-
TYPE)
• A procedure may have input and output paramters:– CREATE PROCEDURE proc1 (INOUT varname DATA-
TYPE)
Executable Section
• BEGINStatements
• END
Examples of parametersCREATE PROCEDURE proc_IN (IN var1 INT) BEGIN SELECT var1 + 2 AS result; END
CREATE PROCEDURE proc_OUT(OUT var1 VARCHAR(100)) BEGIN SET var1 = 'This is a test'; END
CREATE PROCEDURE proc_INOUT (IN var1 INT,OUT var2 INT) BEGIN SET var2 = var1 * 2; END
Variable Declaration• DECLARE variable_name datatype(size) DEFAULT default_value;
• Variable naming rules: Identifiers can consist of any alphanumeric characters, plus the characters '_' and '$'. Identifiers can start with any character that is legal in an identifier, including a digit. However, an identifier cannot consist entirely of digits.
• Data types:A variable can have any MySQL data types. For example:– Character: CHAR(n), VARCHAR(n)– Number: INT, SMALLINT, DECIMAL(i,j), DOUBLE – Date: DATE, TIME, DATETIME– BOOLEAN
• http://www.mysqltutorial.org/mysql-data-types.aspx
Examples
DECLARE x, y INT DEFAULT 0;
DECLARE today TIMESTAMP DEFAULT CURRENT_DATE;
DECLARE ename VARCHAR(50);
DECLARE no_more_rows BOOLEAN;SET no_more_rows = TRUE;
Assigning variables
• Using the SET command:DECLARE total_count INT DEFAULT 0;
SET total_count = 10;
Using the SELECT INTO command:
DECLARE total_products INT DEFAULT 0;
SELECT COUNT(*) INTO total_products
FROM products;
SELECT … INTO
• SELECT columns separated by commas• INTO variables separated by commas• FROM tablename• WHERE condition;• Ex:
– SELECT cid, cname INTO custID, customername– FROM customer– WHERE cid = ‘c01’;
Arithmetic and string operators
• Arithmetic operators:+, -, *, /
• Modulo operator:–% or mod
• Other math calculations use math functions:–Pow(x,y)
• Concatenation uses CONCAT function:–SELECT CONCAT('New ', 'York ', 'City');
MySQL Comparison Operators
• EQUAL(=)
• LESS THAN(<)
• LESS THAN OR EQUAL(<=)
• GREATER THAN(>)
• GREATER THAN OR EQUAL(>=)
• NOT EQUAL(<>,!=)
•
Logical Operators
• Logical AND:– AND, && – UnitsInStock < ReorderLevel AND CategoryID=1
– UnitsInStock < ReorderLevel && CategoryID=1
• Negates value:– NOT, !
• Logical OR:– ||, OR– CategoryID=1 OR CategoryID=8– CategoryID=1 || CategoryID=8
IF statement: The IF statement can have THEN, ELSE, and ELSEIF clauses, and it is
terminated with END IF.
IF variable1 = 0 THEN SELECT variable1; END IF;
IF param1 = 0 THEN SELECT 'Parameter value = 0'; ELSE SELECT 'Parameter value <> 0'; END IF;
CASE StatementCREATE PROCEDURE proc_CASE(IN param1 INT) BEGIN DECLARE variable1 INT; SET variable1 = param1 + 1; CASE variable1 WHEN 0 THEN INSERT INTO table1 VALUES (param1); WHEN 1 THEN INSERT INTO table1 VALUES (variable1); ELSE INSERT INTO table1 VALUES (99); END CASE; END
WHILE cond DO statement
CREATE PROCEDURE proc_WHILE (IN param1 INT) BEGIN DECLARE variable1, variable2 INT; SET variable1 = 0; WHILE variable1 < param1 DO INSERT INTO table1 VALUES (param1); SELECT COUNT(*) INTO variable2 FROM table1; SET variable1 = variable2; END WHILE; END
Comment Syntax
• From a /* sequence to the following */ sequence.
• From a “#” character to the end of the line.
• From a “-- ” sequence to the end of the line. In MySQL, the “-- ” (double-dash) comment style requires the second dash to be followed by at least one whitespace
-- Programmer: John Smith
DELIMITER // CREATE PROCEDURE Caltax(sidIN char(5), taxRate double, out taxOut double) LANGUAGE SQL DETERMINISTIC SQL SECURITY DEFINER COMMENT 'A procedure' BEGIN
DECLARE tax DOUBLE;DECLARE empSalary DOUBLE;select Salary into empSalary from salesreps where sid = sidIN;set taxOut=taxRate*empSalary;
END//
A Procedure to compute tax that takes sidIN and taxRate as inputs and return taxOut as output
• Note 1: No need to surround the sidIN with quotation mark:
select Salary into empSalary from salesreps where sid = sidIN;
• Note 2: The delimiter is changed to // to enable the entire definition to be passed to the server as a single statement. It can be restored to “;” mysql>delimiter ;
User-Defined Temporary Variables
• User variables are written as @var_name.
mysql> SET @t1=1, @t2=2, @t3:=4;mysql> SELECT @t1, @t2, @t3, @t4 := @t1+@t2+@t3;+------+------+------+--------------------+| @t1 | @t2 | @t3 | @t4 := @t1+@t2+@t3 |+------+------+------+--------------------+| 1 | 2 | 4 | 7 | +------+------+------+--------------------+
Example of running the procedure from the command prompt
mysql> delimiter ;mysql> set @tax=0;Query OK, 0 rows affected (0.00 sec)
mysql> call caltax('S1',0.1,@tax);Query OK, 1 row affected (0.00 sec)
mysql> select @tax;+------+| @tax |+------+| 650 |+------+1 row in set (0.00 sec)
DELIMITER //
CREATE PROCEDURE addOrder(oidIN char(5), cidIN char(5), sidIN char(5), odateIN date)
LANGUAGE SQL
DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A procedure'
BEGIN
DECLARE cidTemp char(5) default "x";
select cid into cidTemp from customers where cid = cidIN;
IF cidTemp=cidIN THEN
insert into orders values(oidIN,cidIN,sidIN,odateIN);
END IF;
END
//
First, check if the customer exist before adding a new order
mysql> call addOrder('O8','C12','S1','2013-06-10');Query OK, 0 rows affected, 1 warning (0.00 sec) because C12 not exist!
Using Routines/Execute
Example:Procedure showCustomersDELIMITER //DROP PROCEDURE IF EXISTS showCustomers;CREATE PROCEDURE showCustomers ()LANGUAGE SQL DETERMINISTIC SQL SECURITY DEFINER COMMENT 'A procedure' BEGIN Select * from Customers;END// DELIMITER ;
Using PDO Calling a stored procedure with a SQL Select statement: select * from customers
<?php $dsn = 'mysql:host=localhost;dbname=salesdb'; $username = 'root'; $password = ''; $db = new PDO($dsn, $username, $password); $customers= $db->query('CALL showCustomers()'); echo "<table border=1><tr>" . "<th>CID</th>" . "<th>CName</th>" . "<th>City</th>" . "<th>Rating</th></tr>"; foreach ($customers as $customer){ $cid=$customer["cid"]; //field name is case sensitive $Cname=$customer["cname"]; $City=$customer["city"]; $Rating=$customer["rating"]; echo "<tr><td>$cid</td>" . "<td>$Cname</td>" . "<td>$City</td>" . "<td>$Rating</td></tr>"; }?>
Calling a procedure with OUT parameter
• Must use MySQL temporary @variable to receive the output value.
• Because a stored procedure does not return to PHP anything, it returns the value into the MySQL variable (@return) (scope is in MySQL), so you need to query this variable in a separate call.
Example Using PDO<?php $sid=$_POST["empID"]; $taxRate=$_POST["taxRate"]; $dsn = 'mysql:host=localhost;dbname=salesdb'; $username = 'root'; $password = ''; $db = new PDO($dsn, $username, $password); $db->query("SET @tax=''"); $myquery="call Caltax('" . $sid . "'," . $taxRate . ",@tax)"; echo $myquery; $db->query( $myquery ); $rs = $db->query( 'SELECT @tax;'); // $row = $rs->fetch(PDO::FETCH_NUM); foreach ($rs as $row){ echo "<p>SID: $sid </P>"; echo "<p>Rate: $taxRate </P>"; echo "<p>Tax: $row[0] </P>"; } ?>
A few notes• 1. We need to create a MySQL variable using the
SET command:$db->query("SET @tax=''");
• 2. Passing PHP variables as inputs will not work. This statement does not work:–$db->query( "call Caltax($sid, $taxRate,@tax);" );
• 3. We need to create a string for the Call statement. String input must be quoted:–$myquery="call Caltax('" . $sid . "'," . $taxRate . ",@tax)";
–$db->query( $myquery );
• 4. Then runs a Select command to read the output variables:–$rs = $db->query( 'SELECT @tax;');
Triggers
• A trigger is a program stored in the database and is called automatically when a triggering event occurs.
• It is associated with a table, and that activates when a particular event occurs for the table. Some uses for triggers are to perform checks of values to be inserted into a table or to perform calculations on values involved in an update.
• A trigger is defined to activate when an INSERT, DELETE, or UPDATE statement executes for the associated table. A trigger can be set to activate either before or after the triggering statement.
CREATE TRIGGER Syntax
• trigger_time: It can be BEFORE or AFTER
• trigger_event: Insert, Delete, Update
• Example:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_body
CREATE TRIGGER ratingChanged AFTER UPDATE ON customersFOR EACH ROW
OLD and NEW
• You can refer to columns in the subject table (the table associated with the trigger) by using the aliases OLD and NEW. OLD.col_name refers to a column of an existing row before it is updated or deleted. NEW.col_name refers to the column of a new row to be inserted or an existing row after it is updated.
Example: Customer Rating Change Log
• Table name: CustomerLog
• Fields: CID, Cname, OldRating,NewRating
Demo :New and :Olddelimiter //
DROP TRIGGER IF EXISTS ratingChanged;
CREATE TRIGGER ratingChanged AFTER UPDATE ON customers
FOR EACH ROW
BEGIN
insert into customerlog values(old.cid,old.cname,old.rating,new.rating);
END
//
delimiter ;
Example
mysql> update customers set rating='c' where cid='C1';Query OK, 1 row affected (0.01 sec)Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from customerlog;+-----+-------+-----------+-----------+| cid | Cname | OldRating | NewRating |+-----+-------+-----------+-----------+| C1 | MYERS | A | c |+-----+-------+-----------+-----------+1 row in set (0.00 sec)
delimiter //
DROP TRIGGER IF EXISTS adddetail;
CREATE TRIGGER adddetail AFTER INSERT ON odetails
FOR EACH ROW
BEGIN
DECLARE stocks decimal(5,1);
select onhand into stocks from products where pid=new.pid;
update products set onhand=onhand - new.qty where pid=new.pid;
END
//
delimiter ;
Updating the onhand quantity after a new detail line is added:
Examplemysql> select * from products;+------+---------------+--------+--------+| pid | pname | price | onhand |+------+---------------+--------+--------+| P1 | COMPUTER | 850.00 | 50.0 || P2 | SVGA MONITOR | 300.00 | 25.0 || P3 | LASER PRINTER | 530.00 | 10.0 || P4 | HARD DRIVE | 125.00 | 40.0 || P5 | SERIAL MOUSE | 25.00 | 75.0 || P6 | TAPE BACKUP | 225.00 | 15.0 || P7 | TRACKBALL | 15.00 | 55.0 |+------+---------------+--------+--------+mysql> insert into odetails values('O6','P2',5);Query OK, 1 row affected (0.03 sec)mysql> select * from products;+------+---------------+--------+--------+| pid | pname | price | onhand |+------+---------------+--------+--------+| P1 | COMPUTER | 850.00 | 50.0 || P2 | SVGA MONITOR | 300.00 | 20.0 || P3 | LASER PRINTER | 530.00 | 10.0 || P4 | HARD DRIVE | 125.00 | 40.0 || P5 | SERIAL MOUSE | 25.00 | 75.0 || P6 | TAPE BACKUP | 225.00 | 15.0 || P7 | TRACKBALL | 15.00 | 55.0 |+------+---------------+--------+--------+
User Defined Functions
• Stored functions differ from stored procedures in that stored functions actually return a value.
• Stored functions have only input parameters (if any parameters at all), so the IN , OUT , and INOUT keywords aren’t used.
• Stored functions have no output parameters; instead, you use a RETURN statement to return a value whose type is determined by the RETURNS type statement, which precedes the body of the function.
ExampleDELIMITER // DROP FUNCTION IF EXISTS empTax;CREATE FUNCTION empTax(Salary Decimal(10,2)) RETURNS
Decimal(10,2)BEGIN Declare tax decimal(10,2);if salary < 3000.00 then set tax=salary*0.1;elseif Salary <5000.00 then set tax=Salary*0.2;else set tax=Salary*0.3;end if;return tax;END//
Using the User-defined Function with SQL
mysql> delimiter ;mysql> select sname, emptax(Salary) as tax from salesreps;+-------+---------+| sname | tax |+-------+---------+| PETER | 1950.00 || PAUL | 2160.00 || MARY | 2250.00 |+-------+---------+3 rows in set (0.00 sec)
Example of Using a User-Defined Function
<?php $db = new mysqli('localhost','root','','salesdb'); $rs=$db->query( 'select sname, emptax(Salary) as tax from salesreps' );echo "<table border=1><tr>" . "<th>Sname</th>" . "<th>Tax</th></tr>"; foreach ($rs as $row){ $sname=$row["sname"]; //field name is case sensitive $tax=$row["tax"]; echo "<tr><td>$sname</td>" . "<td>$tax</td></tr>"; }?>
Cursors
• A cursor is a pointer to a set of records returned by a SQL statement. It enables you to take a set of records and deal with it on a row-by-row basis.
Cursor has three important properties
• The cursor will not reflect changes in its source tables.
• Read Only : Cursors are not updatable.
• Not Scrollable : Cursors can be traversed only in one direction, forward, and you can't skip records from fetching.
Defining and Using Cursors• Declare cursor:
– DECLARE cursor-name CURSOR FOR SELECT ...; • DECLARE CONTINUE HANDLER FOR NOT FOUND:
Specify what to do when no more records found– DECLARE b INT;– DECLARE CONTINUE HANDLER FOR NOT FOUND SET b = 1;
Open cursor:OPEN cursor-name;
Fetch data into variables:FETCH cursor-name INTO variable [, variable];
CLOSE cursor:
CLOSE cursor-name;
DELIMITER //
DROP Procedure IF EXISTS maleSum;
CREATE Procedure maleSum(OUT sumSalary Decimal(10,2))
BEGIN
DECLARE Sal,sumSal decimal(10,2);
DECLARE continueFlag int default 0;
DECLARE maleCursor CURSOR FOR SELECT Salary FROM salesreps where sex='M';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET continueFlag = 1;
OPEN maleCursor;
SET Sal = 0;
SET sumSal= 0;
WHILE continueFlag = 0 DO
FETCH maleCursor INTO Sal;
IF continueFlag = 0 THEN
SET sumSal = sumSal+Sal;
END IF;
END WHILE;
CLOSE maleCursor;
SET sumSalary=sumSal;
END
//
Cursor Example
DELIMITER //DROP PROCEDURE IF EXISTS emailgroup;CREATE PROCEDURE emailgroup (INOUT emaillist varchar(4000))LANGUAGE SQL DETERMINISTIC SQL SECURITY DEFINER COMMENT 'A procedure' BEGIN DECLARE continueFlag INTEGER DEFAULT 0; DECLARE useremail varchar(100) DEFAULT ""; DEClARE email_cursor CURSOR FOR SELECT email FROM users; DECLARE CONTINUE HANDLER FOR NOT FOUND SET continueFlag = 1; OPEN email_cursor; WHILE continueFlag = 0 DO
FETCH email_cursor INTO useremail; IF continueFlag = 0 THEN
SET emaillist = CONCAT(useremail,";",emaillist); END IF; END WHILE; CLOSE email_cursor;END// DELIMITER ;
A procedure to create email list using cursor