写在前面

此处是数据库的脚本(建表语句,包括数据),执行方法这里就不介绍了!classicmodels.sql

一、第一个入门示例,创建存储过程,getAllProducts

USE classicmodels;-- 选择数据库
SHOW TABLES;
delimiter //
CREATE PROCEDURE getAllProducts ()
BEGIN
	SELECT * FROM products ;
END //
delimiter ;
-- 调用存储过程 getAllProducts
CALL getAllproducts();
 -- 这里会正确返回findAll

二、第二节,存储过程变量

-- 声明变量(在存储过程内部)
-- DECLARE 变量名 变量类型 (size) DEFAULT default_value;

– 声明如下
– DECLARE a INT DEFAULT 1;
– DECLARE x,y INT DEFAULT 0;

– 可同时声明多个变量
– DECLARE total_count INT;
– SET total_count = 10;

三、存储过程参数,IN,OUT,INOUT

– IN/OUT/INOUT 名字 类型,IN/OUT/INOUT 名字 类型,IN/OUT/INOUT 名字 类型
– 以逗号隔开,可传多个

– 实例

delimiter //
CREATE PROCEDURE getOfficeByCountry (IN countryName VARCHAR(255))
BEGIN
	SELECT
		*
	FROM
		offices
	WHERE
		country = countryName ;
END //
delimiter ;
-- 调用存储过程
call getOfficeByCountry('usa');
call getOfficeByCountry('france');

– OUT 参数示例

delimiter //
CREATE PROCEDURE CountOrderByStatus (
	IN orderStatus VARCHAR (255),
	OUT total INT
)
BEGIN
	SELECT
		count(orderStatus) INTO total
	FROM
		orders
	WHERE
		STATUS = orderStatus ;
END //
delimiter ;
-- 调用存储过程
call CountOrderByStatus('Shipped',@total);
SELECT @total;
call CountOrderByStatus('Shipped',@aa);
SELECT @aa;

– INOUT 参数示例

delimiter //
CREATE PROCEDURE set_counter (
	INOUT count INT (4),
	IN inc INT (4)
)
BEGIN
	SET count = count + inc ;
END //
delimiter ;
-- 这个怎么运行,调用
SET @counter = 1;
CALL set_counter (@counter, 1);
SELECT @counter ;-- 返回 2
call set_counter(@counter,6);
SELECT @counter ;-- 返回 8

第四节 多个返回参数的时候

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 //
DELIMITER ;
-- 调用存储过程,输出时按存储过程的输出顺序,输出对应字段
CALL get_order_by_cust (141 ,@a ,@b ,@c ,@d);
SELECT @a total_shiped ,@b total_canceled ,@c ,@d total_disputed ;

第五节 MYSQL 的 if 声明

-- 句式 1
	-- IF expression THEN
	-- 	statements;
	-- END
	-- IF;

-- 句式 2
-- IF expression THEN
-- 	statements;
-- ELSE
-- 	- statements;
-- END IF;

-- 句式 3
-- IF expression THEN
-- 	statements;
-- ELSEIF
-- ELSEIF - expression THEN
-- ELSEIF - statements;
-- ..
-- ELSE
-- ELSE
-- 	- statements;
-- END IF;

– MySQL IF语句示例

delimiter //
CREATE PROCEDURE GetCustomerLevel (
	IN p_customerNumber INT (11),
	OUT p_customerLevel VARCHAR (10)
)
BEGIN
	DECLARE creditlim DOUBLE ; 
	 SELECT creditlimit INTO creditlim
		FROM customers WHERE customerNumber = p_customerNumber;
		IF creditlim > 50000 THEN
				SET p_customerLevel = 'PLATINUM' ;
		ELSEIF (creditlim <= 50000 AND creditlim >= 10000) THEN
				SET p_customerLevel = 'GOLD' ;
		ELSEIF creditlim < 10000 THEN
				SET p_customerLevel = 'SILVER' ;
		END IF ;
END //-- 老是会报错,即使复制过来也是,因为 末尾的 // 

delimiter ;
CALL GetCustomerLevel (144 ,@customerLevel) ;
SELECT @customerLevel ;

第六节 MySQL CASE语句

-- 声明定义
	-- 	CASE case_expression
	-- 	WHEN when_expression_1 THEN
	-- 			commands
	-- 	WHEN when_expression_2 THEN
	-- 			commands...
	-- 	ELSE
	-- 			commands
	-- 	END CASE;

– 简单 CASE 示例一

DELIMITER //
CREATE PROCEDURE GetCustomerShipping (
   IN p_customerNumber INT (11),
   OUT p_shiping VARCHAR (50)
)
BEGIN
   DECLARE customerCountry VARCHAR (50) ; 
   SELECT country INTO customerCountry FROM customers
   	WHERE customerNumber = p_customerNumber ; 
   	CASE customerCountry
   	WHEN 'USA' THEN
   			SET p_shiping = '2-day Shipping' ;
   	WHEN 'Canada' THEN
   			SET p_shiping = '3-day Shipping' ;
   	ELSE
   			SET p_shiping = '5-day Shipping' ;
   	END CASE ;
END //
delimiter ;

调用存储过程

CALL GetCustomerShipping(144,@p_shiping);
SELECT @p_shiping;

– SQL测试脚本,可一键运行,输出结果

SET @customerNo = 112;
 
SELECT country into @country
FROM customers
WHERE customernumber = @customerNo;
 
CALL GetCustomerShipping(@customerNo,@shipping);
 
SELECT @customerNo AS Customer,
       @country    AS Country,
       @shipping   AS Shipping; -- USA	2-day Shipping	112
-- 搜索 CASE 的 statement 
-- 	CASE
--     WHEN condition_1 THEN commands
--     WHEN condition_2 THEN commands
--     ...
--     ELSE commands
-- 	END CASE;

CASE示例 二

DELIMITER //
CREATE PROCEDURE GetCustomerLevel_2 (
	IN p_customerNumber INT (11),
	OUT p_customerLevel VARCHAR (10)
)
BEGIN
	DECLARE
		creditlim DOUBLE ; SELECT
			creditlimit INTO creditlim
		FROM
			customers
		WHERE
			customerNumber = p_customerNumber ; CASE
		WHEN creditlim > 50000 THEN
		SET p_customerLevel = 'PLATINUM' ;
		WHEN (
			creditlim <= 50000
			AND creditlim >= 10000
		) THEN
		SET p_customerLevel = 'GOLD' ;
		WHEN creditlim < 10000 THEN

		SET p_customerLevel = 'SILVER' ;
		END CASE ; 
END //
delimiter ;

– 测试脚本 2

CALL GetCustomerLevel_2(144,@p_customerLevel);
SELECT @p_customerLevel as customerLevel; -- PLATINUM

第七节 如何在 IF 和 CASE 语句之间选择

– 首先考虑以下几点
– 一个简单的CASE语句是不是更可读IF语句,当你对一个范围内唯一值的比较单一的表达。此外,简单CASE语句比IF语句更有效。
– 当您基于多个值检查复杂表达式时,该IF语句更容易理解。
– 如果选择使用该CASE语句,则必须确保至少有一个CASE条件匹配。否则,您需要定义错误处理程序以捕获错误。回想一下,您不必使用该IF语句执行此操作。
– 在大多数组织中,总会有一些称为开发指南的文档,它为开发人员提供了编程风格的命名约定和指南。您应该参考本文档并遵循开发实践。
– 在某些情况下,之间的混合IF,并CASE让您的存储过程更具可读性和效率。

第八节 MySQL 中循环

三种: WHILE,REPEAT 和 LOOP。

8.1 WHILE循环

– WHILE expression DO
– statements
– END WHILE
– 示例

DELIMITER //
-- DROP PROCEDURE IF EXISTS test_mysql_while_loop //
CREATE PROCEDURE test_mysql_while_loop ()
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 //
DELIMITER ;

调用函数

call test_mysql_while_loop();

8.2 REPEAT循环

– REPEAT
– statements;
– UNTIL expression – 注意UNTIL 表达式中没有分号 “;”
– END REPEAT

示例 repeated

   	DELIMITER //
DROP PROCEDURE IF EXISTS mysql_test_repeat_loop //
   	CREATE PROCEDURE mysql_test_repeat_loop ()
   	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 //
   	DELIMITER ; 

– 调用函数
CALL mysql_test_repeat_loop();

-- 8.3 LOOP循环
-- LOOP,LEAVE和ITERATE语句

– 示例

delimiter //
CREATE PROCEDURE test_mysql_loop ()
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 //
delimiter ;
	-- 调用存储过程
	call test_mysql_loop();  -- 2,4,6,8,10,

第九节 MySQL Cursor(光标)(只需理解阶段,不做重点)

– MySQL游标是只读的,不可滚动且不敏感的。

– 只读:您无法通过游标更新基础表中的数据。
– 不可滚动:您只能按SELECT语句确定的顺序获取行。您无法以相反的顺序获取行。
– 此外,您不能跳过行或跳转到结果集中的特定行。
– 未定型:有两种光标:未定型游标和不敏感游标。敏感光标指向实际数据,而不敏感光标使用数据的临时副本。
– 敏感性游标比不敏感游标执行得更快,因为它不必创建临时数据副本。但是,对来自其他连接的数据所做的
– 任何更改都将影响敏感光标正在使用的数据,因此,如果不更新敏感光标正在使用的数据,则更安全。MySQL游标是敏感的。

第十节 如何查出MySQL数据库中的存储过程

-- 10.1 展示特征 
	SHOW PROCEDURE STATUS [LIKE 'pattern' | WHERE expr];	
	-- 	示例
		SHOW PROCEDURE STATUS;
		SHOW PROCEDURE STATUS WHERE db = 'classicmodels';
		SHOW PROCEDURE STATUS WHERE name LIKE '%product%';
-- 10.2 显示存储过程的源代码
	SHOW CREATE PROCEDURE stored_procedure_name;
	SHOW CREATE PROCEDURE getAllProducts;

第十一节 MYSQL中存储过程中的错误处理(了解即可,不做重点)

-- 11.1 声明处理程序
	DECLARE action HANDLER FOR condition_value statement;
	-- 如果条件的值与之匹配  condition_value,MySQL将执行statement并继续或退出当前代码块action。

	-- 所述action接受下列值之一:

	-- CONTINUE:继续执行封闭代码块(BEGIN... END)。
	-- EXIT :声明处理程序的封闭代码块的执行终止。

-- 11.2 MySQL错误处理示例

第十二节 如何使用SIGNAL和RESIGNAL语句来提高存储过程中的错误条件(了解即可,不做重点)

第十三节 MySQL存储函数(一般内置的函数已经可以满足业务需求,这里可自定义函数,并在SQL中调用)

-- 声明 statement
	-- 	CREATE FUNCTION function_name(param1,param2,…)
	--     RETURNS datatype
	--    [NOT] DETERMINISTIC
	-- 	statements

示例

DELIMITER //
CREATE FUNCTION CustomerLevel (p_creditLimit DOUBLE) RETURNS VARCHAR (10) DETERMINISTIC
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 //
delimiter ;

– SQL 测试

SELECT
   	customerName,
   	CustomerLevel (creditLimit)
   FROM
   	customers
   ORDER BY
   	customerName ;

存储过程的学习就到这里!!