MySQL存储过程
2018-08-15 23:00:06
1、存储过程介绍
(1) 定义:存储过程是存储在数据库目录中的一段声明性SQL语句。 触发器,其他存储过程以及java,python,php等应用程序可以调用存储过程。
递归存储过程:自身的存储过程。大多数数据库管理系统支持递归存储过程。 但是,MySQL不支持它。
(2)优点:
1️⃣通常存储过程有助于提高应用程序的性能。当创建,存储过程被编译之后,就存储在数据库中。 但是,MySQL实现的存储过程略有不同。 MySQL存储过程按需编译。 在编译存储过程之后,MySQL将其放入缓存中。 MySQL为每个连接维护自己的存储过程高速缓存。 如果应用程序在单个连接中多次使用存储过程,则使用编译版本,否则存储过程的工作方式类似于查询。
2️⃣存储过程有助于减少应用程序和数据库服务器之间的流量,因为应用程序不必发送多个冗长的SQL语句,而只能发送存储过程的名称和参数。
3️⃣存储的程序对任何应用程序都是可重用的和透明的。 存储过程将数据库接口暴露给所有应用程序,以便开发人员不必开发存储过程中已支持的功能。
4️⃣存储的程序是安全的。 数据库管理员可以向访问数据库中存储过程的应用程序授予适当的权限,而不向基础数据库表提供任何权限。
(3)缺点:
1️⃣如果使用大量存储过程,那么使用这些存储过程的每个连接的内存使用量将会大大增加。 此外,如果您在存储过程中过度使用大量逻辑操作,则CPU使用率也会增加,因为数据库服务器的设计不当于逻辑运算。
2️⃣存储过程的构造使得开发具有复杂业务逻辑的存储过程变得更加困难。
3️⃣很难调试存储过程。
4️⃣开发和维护存储过程并不容易。
2、存储过程入门
在Navicat命令行下创建第一个存储过程HelloProcedure(),也可以直接使用navicat中的图形化界面直接创建,也可以用MySQL Workbench图形化工具创建。
mysql> delimiter // ---将分隔符;改为// mysql> drop procedure if exists HelloProcedure; ---不要括弧! -> // Query OK, 0 rows affected mysql> create procedure HelloProcedure() -> begin -> select * from products; -> end// Query OK, 0 rows affected mysql> delimiter ; ---将分隔符改回来 mysql> call HelloProcedure(); ---调用存储过程,要带括弧!
第一个命令是DELIMITER //
,它与存储过程语法无关。 DELIMITER
语句将标准分隔符 - 分号(;
)更改为://
。 在这种情况下,分隔符从分号(;
)更改为双斜杠//
。
为什么我们必须更改分隔符? 因为我们想将存储过程作为整体传递给服务器,而不是让mysql工具一次解释每个语句。 在END
关键字之后,使用分隔符//
来指示存储过程的结束。 最后一个命令(DELIMITER;
)将分隔符更改回分号(;
)。
3、存储过程变量
声明变量: declare x int default 0; declare x, y int default 0; ---可以同时声明多个变量 分配变量值: declare total int default 0; set total = 10; ---分配给total的值为10 declare total int default 0; select count(*) into total from products; ---将sql语句的查询结果分配给total 变量范围(作用域): 在存储过程中声明一个变量,那么当达到存储过程的END语句时,它将超出范围,因此在其它代码块中无法访问。 以@符号开头的变量是会话变量。直到会话结束前它可用和可访问。
4、存储过程参数
参数有三种:
- IN---是默认模式。在存储过程中定义
IN
参数时,调用程序必须将参数传递给存储过程。 另外,IN
参数的值被保护。这意味着即使在存储过程中更改了IN
参数的值,在存储过程结束后仍保留其原始值。
mysql> drop procedure if exists GetOfficeByCountry; Query OK, 0 rows affected mysql> delimiter // mysql> create procedure GetOfficeByCountry(in countryName varchar(255)) -> begin -> select * -> from offices -> where country = countryName; -> end // Query OK, 0 rows affected mysql> delimiter ; mysql> call GetOfficeByCountry('USA'); +------------+---------------+-----------------+----------------------+--------------+-------+---------+------------+-----------+ | officeCode | city | phone | addressLine1 | addressLine2 | state | country | postalCode | territory | +------------+---------------+-----------------+----------------------+--------------+-------+---------+------------+-----------+ | 1 | San Francisco | +1 650 219 4782 | 100 Market Street | Suite 300 | CA | USA | 94080 | NA | | 2 | Boston | +1 215 837 0825 | 1550 Court Place | Suite 102 | MA | USA | 02107 | NA | | 3 | NYC | +1 212 555 3000 | 523 East 53rd Street | apt. 5A | NY | USA | 10022 | NA | +------------+---------------+-----------------+----------------------+--------------+-------+---------+------------+-----------+ 3 rows in set Query OK, 0 rows affected mysql> drop procedure if exists CountOrderByStatus; Query OK, 0 rows affected
- OUT---可以在存储过程中更改
OUT
参数的值,并将其更改后新值传递回调用程序。请注意,存储过程在启动时无法访问OUT
参数的初始值。
mysql> drop procedure if exists CountOrderByStatus; Query OK, 0 rows affected mysql> delimiter // mysql> create procedure CountOrderByStatus(in orderStatus varchar(255),out total int) -> begin -> select count(orderNumber) -> into total -> from orders -> where status = orderStatus; -> end // Query OK, 0 rows affected mysql> delimiter ; mysql> call CountOrderByStatus('Shipped',@total); Query OK, 1 row affected mysql> select @total; +--------+ | @total | +--------+ | 303 | +--------+ 1 row in set
- INOUT---
INOUT
参数是IN
和OUT
参数的组合。这意味着调用程序可以传递参数,并且存储过程可以修改INOUT
参数并将新值传递回调用程序。
mysql> drop procedure if exists set_counter; Query OK, 0 rows affected mysql> delimiter // mysql> create procedure set_counter(inout count int(4),in inc int(4)) -> begin -> set count = count + inc; -> end // Query OK, 0 rows affected mysql> delimiter ; mysql> set @counter = 1; Query OK, 0 rows affected mysql> call set_counter(@counter,1); ---2 Query OK, 0 rows affected mysql> call set_counter(@counter,1); ---3 Query OK, 0 rows affected mysql> call set_counter(@counter,5); ---8 Query OK, 0 rows affected mysql> select @counter; +----------+ | @counter | +----------+ | 8 | +----------+ 1 row in set
5、返回多个值的存储过程
DELIMITER $$ CREATE PROCEDURE get_order_by_cust( IN cust_no INT, OUT shipped INT, OUT canceled INT, OUT resolved INT, OUT disputed INT) BEGIN -- shipped SELECT count(*) INTO shipped FROM orders WHERE customerNumber = cust_no AND status = 'Shipped'; -- canceled SELECT count(*) INTO canceled FROM orders WHERE customerNumber = cust_no AND status = 'Canceled'; -- resolved SELECT count(*) INTO resolved FROM orders WHERE customerNumber = cust_no AND status = 'Resolved'; -- disputed SELECT count(*) INTO disputed FROM orders WHERE customerNumber = cust_no AND status = 'Disputed'; END
6、IF语句(if then else end if;和 if then elseif then else end if;)
mysql> delimiter // mysql> create procedure GetCustomerLevel(in p_cusNum int(11),out p_cusLevel varchar(10)) -> begin -> declare creditlim double; -> -> select creditlimit into creditlim -> from customers -> where customerNumber = p_cusNum; -> -> if creditlim > 50000 then -> set p_cusLevel = 'PLATINUM'; -> elseif (creditlim <= 50000 and creditlim >= 10000) then -> set p_cusLevel = 'GOLD'; -> elseif creditlim < 10000 then -> set p_cusLevel = 'SILVER'; -> end if; -> end // Query OK, 0 rows affected mysql> call GetCustomerLevel(103,@p_cusLevel); -> // Query OK, 1 row affected mysql> delimiter ; mysql> select @p_cusLevel; +-------------+ | @p_cusLevel | +-------------+ | GOLD | +-------------+ 1 row in set
7、CASE语句
case when ... then ...
when ... then ...
else ...
end case;
注意:在select查询语句中,可以直接在end 后面加上字段别名!
case when ... then ...
when ... then ...
else ...
end 字段别名; (或者end as 字段别名)
mysql> delimiter // mysql> create procedure GetCusShipping(in p_cusNum int(11),out p_shipping varchar(50)) -> begin -> declare cusCountry varchar(50); -> -> select country into cusCountry -> from customers -> where customerNumber = p_cusNum; -> -> case cusCountry -> when 'USA' then set p_shipping = '2'; -> when 'Canada' then set p_shipping = '3'; -> else -> set p_shipping = '5'; -> end case; -> end // Query OK, 0 rows affected mysql> delimiter ; mysql> set @p_cusNum = 112; Query OK, 0 rows affected mysql> select country into @country -> from customers -> where customerNumber = @p_cusNum; Query OK, 1 row affected mysql> call GetCusShipping(@p_cusNum,@shipping); Query OK, 1 row affected mysql> select @p_cusNum as Customer, -> @country as Country, -> @shipping as Shipping; +----------+---------+----------+ | Customer | Country | Shipping | +----------+---------+----------+ | 112 | USA | 2 | +----------+---------+----------+ 1 row in set
注意:可以直接在navicatl里面创建存储过程,创建的时候选择参数类型的时候记得加上具体的范围,保存的时候只用写上存储过程的名称,不用带括号。
8、IF和CASE语句使用技巧
IF语句和CASE语句的时候,看个人喜好。
IF判断嵌套少的话,使用IF更方便,但是IF判断嵌套太多的话,建议使用CASE更加简单易读!
9、循环
while...do...end while;
begin declare x int; declare str varchar(255); set x = 1; set str = ''; while x <= 5 do set str = concat(str,x,','); set x = x + 1; end while; select str; end
mysql> call test_mysql_while_loop();
+------------+
| str |
+------------+
| 1,2,3,4,5, |
+------------+
1 row in set
Query OK, 0 rows affected
repeat...until...end repeat;
begin declare x int; declare str varchar(255); set x = 1; set str = ''; repeat set str = concat(str,x,','); set x = x + 1; until x > 5 end repeat; select str; end
mysql> call test_mysql_repeat_loop();
+------------+
| str |
+------------+
| 1,2,3,4,5, |
+------------+
1 row in set
Query OK, 0 rows affected
loop...leave...iterate...; leave相当于break,iterate相当于continue.
begin declare x int; declare str varchar(255); set x = 1; set str = ''; loop_label: loop if x > 10 then leave loop_label; end if; set x = x + 1; if(x mod 2) then iterate loop_label; else set str = concat(str,x,','); end if; end loop; select str; end
mysql> call test_mysql_loop();
+-------------+
| str |
+-------------+
| 2,4,6,8,10, |
+-------------+
1 row in set
Query OK, 0 rows affected
10、游标
要处理存储过程中的结果集,请使用游标。游标允许您迭代查询返回的一组行,并相应地处理每行。
MySQL游标为只读(无法通过光标更新基础表中的数据),不可滚动(只能按照select语句的顺序获取行)和敏感(敏感指向实际数据,不敏感指向数据副本,敏感比不敏感执行的快)。
BEGIN DECLARE v_finished INTEGER DEFAULT 0; DECLARE v_email varchar(100) DEFAULT ""; -- 1、declare cursor for employee email DEClARE email_cursor CURSOR FOR SELECT email FROM employees; -- 2、declare NOT FOUND handler DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1; -- 3、open OPEN email_cursor; get_email: LOOP -- 4、fetch FETCH email_cursor INTO v_email; -- 5、not found IF v_finished = 1 THEN LEAVE get_email; END IF; -- 6、build email list SET email_list = CONCAT(v_email,";",email_list); END LOOP get_email; -- 7、close CLOSE email_cursor; END mysql> set @email_list = ""; Query OK, 0 rows affected mysql> call build_email_list(@email_list); Query OK, 0 rows affected mysql> select @email_list; +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | @email_list | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mgerard@gmail.com;ykato@gmail.com;mnishi@gmail.com;tking@gmail.com;pmarsh@yiibai.com;afixter@yiibai.com;bjones@gmail.com;lbott@yiibai.com;pcastillo@gmail.com;ghernande@gmail.com;lbondur@yiibai.com;gvanauf@yiibai.com;ftseng@yiibai.com;spatterson@yiibai.com;jfirrelli@yiibai.com;lthompson@yiibai.com;ljennings@yiibai.com;abow@gmail.com;gbondur@gmail.com;wpatterson@yiibai.com;jfirrelli@yiibai.com;mpatterso@yiibai.com;dmurphy@yiibai.com; | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set
11、在数据库中列出存储过程
mysql> show procedure status;---列出有权访问的数据库的所有存储过程 +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | Db | Name | Type | Definer | Modified | Created | Security_type | Comment | character_set_client | collation_connection | Database Collation | +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | mydb2 | GetAllByUsername | PROCEDURE | root@localhost | 2018-08-07 17:06:32 | 2018-08-07 17:06:32 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | mydb2 | GetAllUser | PROCEDURE | root@localhost | 2018-08-06 16:14:26 | 2018-08-06 16:14:26 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | mydb2 | GetAllUser2 | PROCEDURE | root@localhost | 2018-08-06 16:21:29 | 2018-08-06 16:21:29 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | AddOrderItem | PROCEDURE | root@localhost | 2018-08-08 11:50:42 | 2018-08-08 11:50:42 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | build_email_list | PROCEDURE | root@localhost | 2018-08-16 10:11:45 | 2018-08-16 10:11:45 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | CountOrderByStatus | PROCEDURE | root@localhost | 2018-08-07 19:23:47 | 2018-08-07 19:23:47 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | Divide | PROCEDURE | root@localhost | 2018-08-08 14:30:07 | 2018-08-08 14:30:07 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCusShipping | PROCEDURE | root@localhost | 2018-08-16 09:20:51 | 2018-08-16 09:20:51 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | GetCustomerLevel | PROCEDURE | root@localhost | 2018-08-07 22:41:38 | 2018-08-07 22:41:38 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCustomerLevel2 | PROCEDURE | root@localhost | 2018-08-08 14:57:09 | 2018-08-08 14:57:09 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCustomerShipping | PROCEDURE | root@localhost | 2018-08-07 22:57:06 | 2018-08-07 22:57:06 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetOfficeByCountry | PROCEDURE | root@localhost | 2018-08-07 19:02:53 | 2018-08-07 19:02:53 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | get_order_by_cust | PROCEDURE | root@localhost | 2018-08-07 19:58:27 | 2018-08-07 19:58:27 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | HelloProcedure | PROCEDURE | root@localhost | 2018-08-15 19:20:34 | 2018-08-15 19:20:34 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | insert_article_tags | PROCEDURE | root@localhost | 2018-08-08 10:57:53 | 2018-08-08 10:57:53 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | insert_article_tags_exit | PROCEDURE | root@localhost | 2018-08-08 11:12:57 | 2018-08-08 11:12:57 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | set_counter | PROCEDURE | root@localhost | 2018-08-07 19:31:14 | 2018-08-07 19:31:14 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | test_mysql_loop | PROCEDURE | root@localhost | 2018-08-16 09:39:36 | 2018-08-16 09:39:36 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | test_mysql_repeat_loop | PROCEDURE | root@localhost | 2018-08-16 09:38:14 | 2018-08-16 09:38:14 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | test_mysql_while_loop | PROCEDURE | root@localhost | 2018-08-16 09:33:52 | 2018-08-16 09:33:52 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ 20 rows in set mysql> show procedure status where db = 'yiibaidb';---列出指定数据库的所有存储过程 +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | Db | Name | Type | Definer | Modified | Created | Security_type | Comment | character_set_client | collation_connection | Database Collation | +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | yiibaidb | AddOrderItem | PROCEDURE | root@localhost | 2018-08-08 11:50:42 | 2018-08-08 11:50:42 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | build_email_list | PROCEDURE | root@localhost | 2018-08-16 10:11:45 | 2018-08-16 10:11:45 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | CountOrderByStatus | PROCEDURE | root@localhost | 2018-08-07 19:23:47 | 2018-08-07 19:23:47 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | Divide | PROCEDURE | root@localhost | 2018-08-08 14:30:07 | 2018-08-08 14:30:07 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCusShipping | PROCEDURE | root@localhost | 2018-08-16 09:20:51 | 2018-08-16 09:20:51 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | GetCustomerLevel | PROCEDURE | root@localhost | 2018-08-07 22:41:38 | 2018-08-07 22:41:38 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCustomerLevel2 | PROCEDURE | root@localhost | 2018-08-08 14:57:09 | 2018-08-08 14:57:09 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetCustomerShipping | PROCEDURE | root@localhost | 2018-08-07 22:57:06 | 2018-08-07 22:57:06 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | GetOfficeByCountry | PROCEDURE | root@localhost | 2018-08-07 19:02:53 | 2018-08-07 19:02:53 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | get_order_by_cust | PROCEDURE | root@localhost | 2018-08-07 19:58:27 | 2018-08-07 19:58:27 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | HelloProcedure | PROCEDURE | root@localhost | 2018-08-15 19:20:34 | 2018-08-15 19:20:34 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | insert_article_tags | PROCEDURE | root@localhost | 2018-08-08 10:57:53 | 2018-08-08 10:57:53 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | insert_article_tags_exit | PROCEDURE | root@localhost | 2018-08-08 11:12:57 | 2018-08-08 11:12:57 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | set_counter | PROCEDURE | root@localhost | 2018-08-07 19:31:14 | 2018-08-07 19:31:14 | DEFINER | | utf8 | utf8_general_ci | utf8_general_ci | | yiibaidb | test_mysql_loop | PROCEDURE | root@localhost | 2018-08-16 09:39:36 | 2018-08-16 09:39:36 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | test_mysql_repeat_loop | PROCEDURE | root@localhost | 2018-08-16 09:38:14 | 2018-08-16 09:38:14 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | | yiibaidb | test_mysql_while_loop | PROCEDURE | root@localhost | 2018-08-16 09:33:52 | 2018-08-16 09:33:52 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | +----------+--------------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ 17 rows in set mysql> show procedure status where name like '%product%'; Empty set mysql> show procedure status where name like '%email%';---列出指定名称的存储过程 +----------+------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | Db | Name | Type | Definer | Modified | Created | Security_type | Comment | character_set_client | collation_connection | Database Collation | +----------+------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ | yiibaidb | build_email_list | PROCEDURE | root@localhost | 2018-08-16 10:11:45 | 2018-08-16 10:11:45 | DEFINER | | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | +----------+------------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+ 1 row in set mysql> show create procedure build_email_list;---列出存储过程的源代码 +------------------+----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+ | Procedure | sql_mode | Create Procedure | character_set_client | collation_connection | Database Collation | +------------------+----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+ | build_email_list | STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `build_email_list`(INOUT email_list varchar(4000)) BEGIN DECLARE v_finished INTEGER DEFAULT 0; DECLARE v_email varchar(100) DEFAULT ""; -- 1、declare cursor for employee email DEClARE email_cursor CURSOR FOR SELECT email FROM employees; -- 2、declare NOT FOUND handler DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1; -- 3、open OPEN email_cursor; get_email: LOOP -- 4、fetch FETCH email_cursor INTO v_email; -- 5、not found IF v_finished = 1 THEN LEAVE get_email; END IF; -- 6、build email list SET email_list = CONCAT(v_email,";",email_list); END LOOP get_email; -- 7、close CLOSE email_cursor; END | utf8mb4 | utf8mb4_general_ci | utf8_general_ci | +------------------+----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+ 1 row in set
12、存储过程中的MySQL错误处理
BEGIN #Routine body goes here... DECLARE EXIT HANDLER FOR 1062 SELECT 'Duplicate keys error encountered'; DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'SQLException encountered'; DECLARE EXIT HANDLER FOR SQLSTATE '23000' SELECT 'SQLSTATE 23000'; INSERT INTO article_tags(article_id,tag_id) VALUES(article_id,tag_id); SELECT COUNT(*) FROM article_tags; END
插入重复的值得时候会报错!处理程序优先级:每一个mysql错误都对应一个错误代码(例如1062),所以处理错误优先级是错误越具体,优先级越高。
mysql> call insert_article_tags_3(1,3);
+----------------------------------+
| Duplicate keys error encountered |
+----------------------------------+
| Duplicate keys error encountered |
+----------------------------------+
1 row in set
Query OK, 0 rows affected
使用命名错误条件:
也就是给错误代码1051取个好理解的名字,这样发生对应的错误的时候,知道具体是什么错误。
DECLARE table_not_found CONDITION for 1051; DECLARE EXIT HANDLER FOR table_not_found SELECT 'Please create table abc first'; SELECT * FROM abc;
13、使用MySQL SIGNAL/RESIGNAL语句引发错误条件
DELIMITER $$ CREATE PROCEDURE AddOrderItem(in orderNo int, in productCode varchar(45), in qty int,in price double, in lineNo int ) BEGIN DECLARE C INT; SELECT COUNT(orderNumber) INTO C FROM orders WHERE orderNumber = orderNo; -- check if orderNumber exists IF(C != 1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Order No not found in orders table'; END IF; -- more code below -- ... END $$ DELIMITER ;
DELIMITER $$ CREATE PROCEDURE Divide(IN numerator INT, IN denominator INT, OUT result double) BEGIN DECLARE division_by_zero CONDITION FOR SQLSTATE '22012'; DECLARE CONTINUE HANDLER FOR division_by_zero RESIGNAL SET MESSAGE_TEXT = 'Division by zero / Denominator cannot be zero'; -- IF denominator = 0 THEN SIGNAL division_by_zero; ELSE SET result := numerator / denominator; END IF; END $$ DELIMITER ;
14、存储函数
存储的函数是返回单个值的特殊类型的存储程序。您使用存储的函数来封装在SQL语句或存储的程序中可重用的常用公式或业务规则。
可以在sql语句中和存储过程中调用存储函数,这样有助于代码的可读性和可维护性。
BEGIN DECLARE lvl varchar(10); IF p_creditLimit > 50000 THEN SET lvl = 'PLATINUM'; ELSEIF (p_creditLimit <= 50000 AND p_creditLimit >= 10000) THEN SET lvl = 'GOLD'; ELSEIF p_creditLimit < 10000 THEN SET lvl = 'SILVER'; END IF; RETURN (lvl); END
mysql> select customerName,CustomerLevel(creditLimit) -> from customers -> order by customerName; +------------------------------------+----------------------------+ | customerName | CustomerLevel(creditLimit) | +------------------------------------+----------------------------+ | Alpha Cognac | PLATINUM | | American Souvenirs Inc | SILVER | | Amica Models & Co. | PLATINUM | | ANG Resellers | SILVER | | Anna's Decorations, Ltd | PLATINUM | | Anton Designs, Ltd. | SILVER | | Asian Shopping Network, Co | SILVER | | Asian Treasures, Inc. | SILVER | | Atelier graphique | GOLD | | Australian Collectables, Ltd | PLATINUM | | Australian Collectors, Co. | PLATINUM | | Australian Gift Network, Co | PLATINUM | | Auto Associs & Cie. | PLATINUM | | Auto Canal+ Petit | PLATINUM | | Auto-Moto Classics Inc. | GOLD | | AV Stores, Co. | PLATINUM | | Baane Mini Imports | PLATINUM | | Bavarian Collectables Imports, Co. | PLATINUM | | BG&E Collectables | SILVER | | Blauer See Auto, Co. | PLATINUM | | Boards & Toys Co. | GOLD | | CAF Imports | PLATINUM | | Cambridge Collectables Co. | GOLD | | Canadian Gift Exchange Network | PLATINUM | | Classic Gift Ideas, Inc | PLATINUM | | Classic Legends Inc. | PLATINUM | | Clover Collections, Co. | PLATINUM | | Collectable Mini Designs Co. | PLATINUM | | Collectables For Less Inc. | PLATINUM | | Corporate Gift Ideas Co. | PLATINUM | | Corrida Auto Replicas, Ltd | PLATINUM | | Cramer Spezialitten, Ltd | SILVER | | Cruz & Sons Co. | PLATINUM | | Daedalus Designs Imports | PLATINUM | | Danish Wholesale Imports | PLATINUM | | Der Hund Imports | SILVER | | Diecast Classics Inc. | PLATINUM | | Diecast Collectables | PLATINUM | | Double Decker Gift Stores, Ltd | GOLD | | Down Under Souveniers, Inc | PLATINUM | | Dragon Souveniers, Ltd. | PLATINUM | | Enaco Distributors | PLATINUM | | Euro+ Shopping Channel | PLATINUM | | Extreme Desk Decorations, Ltd | PLATINUM | | Feuer Online Stores, Inc | SILVER | | Franken Gifts, Co | SILVER | | Frau da Collezione | GOLD | | FunGiftIdeas.com | PLATINUM | | Gift Depot Inc. | PLATINUM | | Gift Ideas Corp. | GOLD | | Gifts4AllAges.com | GOLD | | giftsbymail.co.uk | PLATINUM | | GiftsForHim.com | PLATINUM | | Handji Gifts& Co | PLATINUM | | Havel & Zbyszek Co | SILVER | | Heintze Collectables | PLATINUM | | Herkku Gifts | PLATINUM | | Iberia Gift Imports, Corp. | PLATINUM | | Kelly's Gift Shop | PLATINUM | | King Kong Collectables, Co. | PLATINUM | | Kommission Auto | SILVER | | Kremlin Collectables, Co. | SILVER | | L'ordine Souveniers | PLATINUM | | La Corne D'abondance, Co. | PLATINUM | | La Rochelle Gifts | PLATINUM | | Land of Toys Inc. | PLATINUM | | Lisboa Souveniers, Inc | SILVER | | Lyon Souveniers | PLATINUM | | Marseille Mini Autos | PLATINUM | | Marta's Replicas Co. | PLATINUM | | Men 'R' US Retailers, Ltd. | PLATINUM | | Messner Shopping Network | SILVER | | Microscale Inc. | GOLD | | Mini Auto Werke | GOLD | | Mini Caravy | PLATINUM | | Mini Classics | PLATINUM | | Mini Creations Ltd. | PLATINUM | | Mini Gifts Distributors Ltd. | PLATINUM | | Mini Wheels Co. | PLATINUM | | Mit Vergngen & Co. | SILVER | | Motor Mint Distributors Inc. | PLATINUM | | Muscle Machine Inc | PLATINUM | | Natrlich Autos | SILVER | | Norway Gifts By Mail, Co. | PLATINUM | | Online Diecast Creations Co. | PLATINUM | | Online Mini Collectables | PLATINUM | | Osaka Souveniers Co. | PLATINUM | | Oulu Toy Supplies, Inc. | PLATINUM | | Petit Auto | PLATINUM | | Porto Imports Co. | SILVER | | Precious Collectables | SILVER | | Qubec Home Shopping Network | GOLD | | Raanan Stores, Inc | SILVER | | Reims Collectables | PLATINUM | | Rovelli Gifts | PLATINUM | | Royal Canadian Collectables, Ltd. | PLATINUM | | Royale Belge | GOLD | | Salzburg Collectables | PLATINUM | | SAR Distributors, Co | SILVER | | Saveley & Henriot, Co. | PLATINUM | | Scandinavian Gift Ideas | PLATINUM | | Schuyler Imports | SILVER | | Signal Collectibles Ltd. | PLATINUM | | Signal Gift Stores | PLATINUM | | Souveniers And Things Co. | PLATINUM | | Stuttgart Collectable Exchange | SILVER | | Stylish Desk Decors, Co. | PLATINUM | | Suominen Souveniers | PLATINUM | | Super Scale Inc. | PLATINUM | | Technics Stores Inc. | PLATINUM | | Tekni Collectables Inc. | GOLD | | The Sharp Gifts Warehouse | PLATINUM | | Tokyo Collectables, Ltd | PLATINUM | | Toms Spezialitten, Ltd | PLATINUM | | Toys of Finland, Co. | PLATINUM | | Toys4GrownUps.com | PLATINUM | | UK Collectables, Ltd. | PLATINUM | | Vida Sport, Ltd | PLATINUM | | Vitachrome Inc. | PLATINUM | | Volvo Model Replicas, Co | PLATINUM | | Warburg Exchange | SILVER | | West Coast Collectables Co. | PLATINUM | +------------------------------------+----------------------------+ 122 rows in set