存储程序可以分为存储过程和函数。在MySQL中,创建存储过程和函数使用的语句分别是CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句来调用存储过程,只能用输出变量返回值。函数可以从语句外调用(引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。
一句话解释存储过程/函数----------------就是提前将我们常用的一些查询存储起来,用的时候直接通过别名调用,非常的方便;
当我们经常要查询某张表的信息的时候,不用每次都输入重复的代码,而是将该代码通过一点过方式存储起来,下次用的时候直接通过过程名调用即可;
使用存储过程将简化操作,减少冗余的操作步骤,同时,还可以减少操作过程中的失误,提高效率;
-- 格式---- delimiter ;; create procedure 过程名([参数1,参数2,.......]) [存储过程特性] begin -- 开始事务 过程内容 end ;; -- 结束事务 dilimiter ; -- 改回原来的结束符 -- 调用过程 call 过程名([参数1,参数2,....]) -- [] 内为可选内容 /*参数中的内容---- [in|out|inout] 参数名 参数类型 其中,IN表示输入参数,OUT表示输出参数,INOUT表示既可以输入也可以输出;param_name表示参数名称;type表示参数的类型,该类型可以是MySQL数据库中的任意类型*/ /* 存储过程/函数的特性--- ● LANGUAGE SQL:说明routine_body部分是由SQL语句组成的, 当前系统支持的语言为SQL。SQL是LANGUAGE特性的唯一值。 ● [NOT] DETERMINISTIC:指明存储过程执行的结果是否正确。 DETERMINISTIC表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。 NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为NOT DETERMINISTIC。 ● { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIESSQL DATA }:指明子程序使用SQL语句的限制。CONTAINS SQL表明子程序包含SQL语句,但是不包含读写数据的语句; NO SQL表明子程序不包含SQL语句; READS SQL DATA说明子程序包含读数据的语句; MODIFIES SQL DATA表明子程序包含写数据的语句。 默认情况下,系统会指定为CONTAINS SQL。 ● SQL SECURITY { DEFINER | INVOKER }:指明谁有权限来执行。 DEFINER表示只有定义者才能执行。 INVOKER表示拥有权限的调用者可以执行。默认情况下,系统指定为DEFINER。 ● COMMENT 'string':注释信息,可以用来描述存储过程或函数。 */
例如以下操作---------------->>>>
-- 创建存储过程----- mysql> delimiter / -- 更改结束符 mysql> create procedure search() -- 此存储过程没有参数,但是后面的()仍然需要 -> begin -> select * from emp ; -> end / Query OK, 0 rows affected (0.04 sec) mysql> delimiter ; -- 改回原来的结束符 -- 调用存储过程 mysql> call search(); +-------+--------+-----------+------+------------+---------+---------+--------+ | EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | +-------+--------+-----------+------+------------+---------+---------+--------+ | 7367 | NULL | NULL | NULL | NULL | NULL | NULL | 40 | | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 | | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | | 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | | 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | | 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | | 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | | 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | | 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | | 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | | 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | | 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | | 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | | 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | +-------+--------+-----------+------+------------+---------+---------+--------+ 15 rows in set (0.00 sec) Query OK, 0 rows affected (0.10 sec)
练习------
– 查询当月应发的总薪资 ,因为每个月都要发,所以可以设置为过程
mysql> delimiter ;; mysql> create procedure salaryAll(out param double) -> begin -> select sum(sal+ifnull(comm,0)) 当月应发总薪资 from emp; -> end ;; Query OK, 0 rows affected (0.05 sec) mysql> delimiter ; mysql> call salaryall(@sal);-- 这里参数是一个变量, +----------------+ | 当月应发总薪资 | +----------------+ | 31225.00 | +----------------+ 1 row in set (0.02 sec) mysql> call salaryall(@empno);----调用无关列,但是参数类型相同 +----------------+ | 当月应发总薪资 | +----------------+ | 31225.00 | +----------------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.01 sec) mysql> call salaryall(@ename);----调用无关列,但是参数类型不同 +----------------+ | 当月应发总薪资 | +----------------+ | 31225.00 | +----------------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.01 sec) -- 可以发现只要输入任何参数符合数据即可求出当月应发薪资,所以有时候要对参数做一些限制;
-- 格式-- delimiter ;; create function 函数名 ([参数1,参数2,......]) returns type [函数特性] return 函数内容 ;; delimiter ; --调用 select 存储函数名(参数....)
内容解析基本跟存储过程一样;
mysql> delimiter ;; mysql> create function nameall() -> returns varchar(20) -> return ( select ename from emp where empno=7893) -> ;; -- 错误提示 没有函数特性来约束, --- 解决方式---- -- 1,添加函数特性约束; -- 2 ,设置| log_bin_trust_function_creators 为ON状态 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) mysql> show variables like '%trust%'; -> ;; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin_trust_function_creators | OFF | +---------------------------------+-------+ 1 row in set, 1 warning (0.00 sec) mysql> set global log_bin_trust_function_creators = 'on'; Query OK, 0 rows affected (0.00 sec) mysql> delimiter ;; mysql> create function test() -> returns varchar(20) -- 函数返回值类型 -> return (select ename from emp where empno=7893)-- 执行的操作 -> ;; Query OK, 0 rows affected (0.03 sec) -- 调用存储函数-- mysql> delimiter ; mysql> select test(); +--------+ | test() | +--------+ | NULL |----创建存储函数时empno 值写错了 +--------+ 1 row in set (0.02 sec) -- 将表中king的empno数据改为7893,在执行 mysql> select test(); +--------+ | test() | +--------+ | KING | +--------+ 1 row in set (0.00 sec) -- 这里强调一下为了安全建议不要开启log_bin_trust_function_creators ,而是为存储函数添加存储特性来解决上述ERROR 1418 (HY000):问题
添加函数存储特性----
mysql> set global log_bin_trust_function_creators = 'off'; Query OK, 0 rows affected (0.00 sec) -- 创建存储函数 mysql> delimiter ;; mysql> create function find() -> returns varchar(20) -> READS SQL DATA -> return (select empno from emp where ename='KING' ) -> ;; -- 调用 mysql> select find(); +--------+ | find() | +--------+ | 7893 | +--------+ 1 row in set (0.00 sec)
如果在存储函数中的return语句跟returns返回值类型不一样,那么返回值会被强制准换为恰当的类型
如果函数返回值为varchar(20) 但是return返回的是一个整数,那么该整数会被转换成varchar类型;
举个例子----
mysql> delimiter ;; mysql> create function find2() -> returns varchar(2) -> READS SQL DATA -> return (select empno from emp where ename='KING' ) -> ;; Query OK, 0 rows affected (0.03 sec) mysql> delimiter ; mysql> select find2(); ERROR 1406 (22001): Data too long for column 'find2()' at row 2 mysql> delimiter ;; mysql> create function find5() -> returns int(2) -> READS SQL DATA -> return (select empno from emp where ename='KING' ) -> ;; Query OK, 0 rows affected, 1 warning (0.03 sec) mysql> delimiter ; mysql> select find5(); +---------+ | find5() | +---------+ | 7893 | +---------+ 1 row in set (0.00 sec)
可以发现int被转换换成了字符串类型,由于长度要求为2个,所以会提示ERROR 1406 (22001):错误;但是如果为int类型的即使指定显示宽度也会将内容显示出来;
小结----
指定参数为IN、OUT或INOUT只对PROCEDURE是合法的。(FUNCTION中总是默认为IN参数)。RETURNS子句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。
变量可以在存储过程中声明并使用,这些变量的作用范围是在BEGIN…END程序中;
--语法格式-- declare 变量名 变量数据类型 [default 默认值]; -- 如果没有default 则默认为该数据类型的默认值--- int 为 0 字符串为 null,类似于java中的默认值; -- 如果为同一类型的变量,则可以写在一起最后定义数据类型 declare a ,b c int; -- 变量值除了可以被声明为一个常数外,还可以是一个表达式;
-- 格式---- set 变量名 =值 set a= 10,b=30; set c=a+b;
还可以将select 语句查询到的值赋值到变量上;
declare id int; declare name varchar(8); select empno ,ename into id ,name from emp where empno=7893;