存储过程

Posted 老螃蟹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了存储过程相关的知识,希望对你有一定的参考价值。

1.声明性SQL语句。 1. 触发器,2. 其他存储过程以及3. Java,Python,php等应用程序可以调用存储过程。

2.mysql主要高级的功能:存储过程,存储函数,触发器和事件  

3.优点是: 减轻web服务器的压力, 将些业务转移到sql 服务器去
4.--------------------------------------
5.创建一个名字叫做:GetAllProducts()的存储过程
DELIMITER //
 CREATE PROCEDURE GetAllProducts()
   BEGIN
   SELECT *  FROM products;
   END //DELIMITER ;
6.调用存储过程
CALL STORED_PROCEDURE_NAME();
7.--------------------------------------
声明变量:DECLARE variable_name datatype(size) DEFAULT default_value;
set分配变量:DECLARE total_count INT DEFAULT 0;SET total_count = 10;
Set Into 分配变量:DECLARE total_products INT DEFAULT 0
SELECT COUNT(*) INTO total_productsFROM products
8.作用域问题: 一般作用域是 begin 到end , 然后加上@ 是属于会话变量,在其他存储过程也可以使用
定义参数:MODE param_name param_type(param_size)
?根据存储过程中参数的目的,MODE可以是IN,OUT或INOUT。
In的实例:USE `yiibaidb`;DROP procedure IF EXISTS `GetOfficeByCountry`;
DELIMITER $$USE `yiibaidb`$$CREATE PROCEDURE GetOfficeByCountry(IN countryName VARCHAR(255))
 BEGIN
 SELECT * 
 FROM offices
 WHERE country = countryName;
 END$$
DELIMITER ;

CALL GetOfficeByCountry(USA);
CALL GetOfficeByCountry(USA);


Out的实例:USE `yiibaidb`;DROP procedure IF EXISTS `CountOrderByStatus`;
DELIMITER $$CREATE PROCEDURE CountOrderByStatus(
 IN orderStatus VARCHAR(25),
 OUT total INT)BEGIN
 SELECT count(orderNumber)
 INTO total
 FROM orders
 WHERE status = orderStatus;END$$DELIMITER ;

CALL CountOrderByStatus(Shipped,@total);
SELECT @total;  #赋值给全局的变量

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); -- 2
CALL set_counter(@counter,1); -- 3
CALL set_counter(@counter,5); -- 8
SELECT @counter; -- 8

9.关于 mybaties中调用存储过程的代码: 
<!-- 调用存储过程递归删除部门以及部门下的所有子部门 -->
    <delete id="deleteProcedureById" statementType="CALLABLE">
      { call delete_department(#{id, mode=IN}) }
   </delete>
根据手册 可以查到, 别照抄老师代码:http://www.mybatis.org/mybatis-3/sqlmap-xml.html

10.返回多个值的存储过程示例
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
11.条件语句
IF expression THEN
   statements;ELSE
   else-statements;END IF;
12.选择语句
CASE  case_expression
   WHEN when_expression_1 THEN commands
   WHEN when_expression_2 THEN commands
   ...
   ELSE commandsEND CASE;
13.循环
WHILE语句的语法如下:
WHILE expression DO
   statementsEND WHILE
WHILE语句的语法如下:
WHILE expression DO
   Statements
END WHILE

 loop_label:  LOOP
 IF  x > 10 THEN 
 LEAVE  loop_label;
 END  IF;
14.游标
存储函数和触发器中使用MySQL游标。
处理存储过程中的结果集,请使用游标。游标允许您迭代查询返回的一组行,并相应地处理每行。
MySQL游标为只读,不可滚动和敏感。
敏感:有两种游标:敏感游标和不敏感游标。敏感游标指向实际数据,不敏感游标使用数据的临时副本。
不可滚动:只能按照SELECT语句确定的顺序获取行,不可 跳转取,不可逆向取

声明游标:
DECLARE cursor_name CURSOR FOR SELECT_statement;
游标声明必须在变量声明之后
OPEN cursor_name;

FETCH cursor_name INTO variables list;
CLOSE cursor_name;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
15.显示存储过程的语句
根据数据库:SHOW PROCEDURE STATUS WHERE db = yiibaidb;
根据存储过程的名字模糊查询:SHOW PROCEDURE STATUS WHERE name LIKE %product%
根据名字直接查询:SHOW CREATE PROCEDURE stored_procedure_name

16.声明处理程序(比如错误)
DECLARE action HANDLER FOR condition_value statement;
SQL
如果条件的值与condition_value匹配,则MySQL将执行statement,并根据该操作继续或退出当前的代码块。
操作(action)接受以下值之一:
?CONTINUE:继续执行封闭代码块(BEGIN ... END)。
?EXIT:处理程序声明封闭代码块的执行终止。
condition_value指定一个特定条件或一类激活处理程序的条件。condition_value接受以下值之一:
?一个MySQL错误代码。
?标准SQLSTATE值或者它可以是SQLWARNING,NOTFOUND或SQLEXCEPTION条件,这是SQLSTATE值类的简写。NOTFOUND条件用于游标或SELECT INTO variable_list语句。
?与MySQL错误代码或SQLSTATE值相关联的命名条件。
例如:DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET has_error = 1;
DECLARE EXIT HANDLER FOR SQLEXCEPTIONBEGINROLLBACK;SELECT An error has occurred, operation rollbacked and the stored procedure was terminated;END;
17.Mysql 处理的优先级, 是错误代码最为具体, 所以错误代码优先级最高
18.声明命名错误的条件:
DECLARE condition_name CONDITION FOR condition_value;

DECLARE table_not_found CONDITION for 1051;DECLARE EXIT HANDLER FOR  table_not_found SELECT Please create table abc first;SELECT * FROM abc;
19.添加返回的错误信息,根据错误码
SIGNAL SQLSTATE 45000
 SET MESSAGE_TEXT = Order No not found in orders table;


 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;
20.存储函数
CREATE FUNCTION function_name(param1,param2,…)
    RETURNS datatype
   [NOT] DETERMINISTIC
 statements
21.
12

2018-01-15

 

------------------------------------------不能下载所以只能贴出来:

题目部分:

1. 利用存储过程求出,product的总数来

2. 将product中的商品数量放置到 变量 total_product中去

3. 根据Country查到office, 要求是输入的变量必须是countryName int

4. 过订单状态返回订单数量。参数分别为:in orderStatus varchar(255) ,out total int

5. 穿入一个参数inout类型 a, 还有一个int类型的参数 b, 存储过程a = a + b, 这样a既是输入也是输出参数

6. 输入4customerNumber ,和status ,来获取, 输入shipped canceled resolved disputed

7. 根据customerNumber获取creditlimit,然后据此进行判断是在哪个区间 10000 50000

8. 根据customerNumber 获取customerCountry, 然后据此进行判断举办活动的时间是几天

9. 将1到5 拼成字符串, while do end while , repeat until end repeat,

10. email_list,字符串放进去,利用游标和concat进行拼接得到varcahr类型

11. 创建一张表, 然后自己做实验, 如果出现重复出现的结果的时候可以报你插入的地方重复插入

 

 

技术分享图片
#1. get allProduct
DELIMITER $$
CREATE PROCEDURE GetAllProduck()
BEGIN
SELECT * FROM products;
END $$
DELIMITER ;

CALL GetAllProduck()

#2. 将product中的商品数量放置到 变量 total_product中去
DELIMITER $$
CREATE PROCEDURE countProduct4()
BEGIN
DECLARE count_products INT DEFAULT 0;
#set count_products = xxx;
SELECT COUNT(*) INTO count_products FROM products;
END $$
DELIMITER ;

#3. 根据countryName 查到office
DELIMITER $$
CREATE    PROCEDURE getOfficeByCountry(IN countryName VARCHAR(255))
BEGIN    
SELECT * FROM offices 
WHERE country = countryName;
END $$

CALL getOfficeByCountry2(China)

#4. 过订单状态返回订单数量
USE yiibaidb;
DROP PROCEDURE IF EXISTS CountryOrderByStatus;

DELIMITER $$
CREATE    PROCEDURE CountryOrderByStatus(IN orderStatus VARCHAR(25), OUT total INT )
BEGIN
SELECT COUNT(orderNumber)
 INTO total 
 FROM orders
WHERE STATUS = orderStatus;
END$$
DELIMITER ;

CALL     CountryOrderByStatus(Shipped, @total);
#  @符号标志的会话变量会等会话结束后才会over, 可以想成一个connection结束。 其他时候可以直接select @变量获得
SELECT    @total;

#5. a = a + b
#use yiibaidb;
DROP PROCEDURE  IF EXISTS addTwoNum ;
DELIMITER $$
CREATE PROCEDURE addTwoNum(INOUT a INT, IN b INT)
BEGIN    
SET a = a + b;
END $$
DELIMITER ; #delimiter 这里必须得空格不然会报错

SET @a = 1;
CALL addTwoNum(@a ,     4);
SELECT @a;

#6. 根据orderNumber, 返回status4种类型的数量
DROP PROCEDURE IF EXISTS get_order_by_cust;

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 = Cancelled;

 -- 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(496, @shipped , @canceled , @resolved , @disputed);
SELECT @shipped , @canceled , @resolved , @disputed;

#7. 根据customerNumber获取creditlimit,然后据此进行判断是在哪个区间 10000 50000

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>10000 AND creditlim<=50000) THEN

SET p_customerLevel = GOLD;

ELSEIF creditlim<=10000 THEN

SET p_customerLevel = SILVER;

END IF;

END $$
DELIMITER ;

CALL GetCustomerLevel(103, @customerLevel);
SELECT @customerLevel;


DELIMITER $$
CREATE PROCEDURE GetCustomerShipping(IN p_customerNumber INT(4),  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  = 4-day Shipping;
END CASE;
END $$
DELIMITER ;

#调用加别名,自己组成表格形式更加好看见       
CALL GetCustomerShipping(112,@shipping);
SELECT @shipping AS Shipping

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;
       

#上一题区间题目用case进行实现
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;

    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$$

#9.将1到5 拼成字符串


#循环遍历while ... do 形式
DELIMITER $$
DROP PROCEDURE IF EXISTS test_mysql_while_loop1$$
CREATE PROCEDURE test_mysql_while_loop1()
BEGIN    
DECLARE X INT(4);
DECLARE str VARCHAR(50);

SET X = 1; 
SET str = ‘‘;

WHILE X <= 5 DO 
SET str = CONCAT(str, X, ,);
SET X = X +1;
END WHILE ;
SELECT str AS num, X AS number;

 END$$
DELIMITER ;

CALL test_mysql_while_loop1;



#循环遍历repeat ... until ... end repeat 形式
DELIMITER $$
DROP PROCEDURE IF EXISTS test_mysql_while_loop2$$
CREATE PROCEDURE test_mysql_while_loop2()
BEGIN    
DECLARE X INT(4);
DECLARE str VARCHAR(50);

SET X = 1; 
SET str = ‘‘;

REPEAT 
SET str = CONCAT(str, X, ,);
SET X = X +1 ;
UNTIL X >5
END REPEAT;
SELECT str AS num, X AS number;

 END$$
DELIMITER ;

CALL test_mysql_while_loop2;




#循环遍历loop_label .... end loop, 中间会有leave loop_label进行退出, Iterate进行迭代
DELIMITER $$
DROP PROCEDURE IF EXISTS test_mysql_while_loop2$$
CREATE PROCEDURE test_mysql_while_loop2()
BEGIN    
DECLARE X INT(4);
DECLARE str VARCHAR(50);

SET X = 1; 
SET str = ‘‘;

 loop_label:  LOOP
 IF  X > 10 THEN 
 LEAVE  loop_label;
 END  IF;

 SET  X = X + 1;
 IF (X MOD 3) THEN
     ITERATE  loop_label;
 ELSE
    SET  str = CONCAT(str,X,,);
 END IF;
    END LOOP;    
SELECT str AS num, X AS number;

 END$$
DELIMITER ;

CALL test_mysql_while_loop2;


#游标的用法,email_list,字符串放进去,利用游标和concat进行拼接得到varcahr类型
DELIMITER $$
DROP PROCEDURE IF EXISTS build_email_list $$
CREATE PROCEDURE build_email_list(INOUT p_email VARCHAR(500))
BEGIN    
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_email VARCHAR(100) DEFAULT ‘‘;

-- declare cusor for the empolyee email
DECLARE email_cusor CURSOR FOR 
SELECT email FROM employees;

-- decalre NOT FOUND hander
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;

OPEN email_cusor;

get_email:LOOP

FETCH email_cusor INTO v_email;

-- 进行跳出判断
IF v_finished = 1 THEN 
LEAVE get_email;
END IF;

SET p_email = CONCAT(v_email, ;, p_email);

END LOOP get_email;

CLOSE email_cusor;

END $$
DELIMITER ;

SET @email_list = "";
CALL build_email_list(@email_list);
SELECT @email_list;

#11. 创建一张表, 然后自己做实验, 如果出现重复出现的结果的时候可以报你插入的地方重复插入, EXITcontinue
DELIMITER $$
DROP PROCEDURE IF EXISTS insertException $$
CREATE PROCEDURE insertException(IN article_id INT, IN tag_id INT )
BEGIN 
-- 进行声明出现重复代码1062的时候输出
 DECLARE CONTINUE HANDLER FOR 1062
 SELECT CONCAT(duplicate found the (,article_id,,,tag_id,)) AS msg;
 
 INSERT INTO article_tags(article_id,tag_id)
 VALUES(article_id,tag_id);

 -- return tag count for the article
 SELECT COUNT(*) FROM article_tags AS a WHERE a.article_id =article_id AND  a.tag_id =tag_id;

END $$
DELIMITER ;

CALL insertException(1,1);
CALL insertException(1,2);
CALL insertException(1,3);



#利用函数进行判断: create function xxx(param )returns type()
#Deterministic ...   return (variable)
- - 
DELIMITER $$
DROP FUNCTION IF EXISTS CustomerLevel6 $$
CREATE FUNCTION CustomerLevel6(p_creditLimit DOUBLE )RETURNS VARCHAR(10)
    DETERMINISTIC
BEGIN 
    DECLARE 1v1 VARCHAR(10);
    
    IF p_creditLimit > 50000 THEN 
  SET 1v1 = jinzi;
    ELSEIF (p_creditLimit > 10000 AND p_creditLimit <= 50000  ) THEN 
  SET 1v1 = yinzi;
     ELSEIF p_creditLimit <= 10000 THEN 
  SET 1v1 = baijin;
  END IF ;
  RETURN (1v1);
  END $$
  DELIMITER ;
  

SELECT 
    customerName, CustomerLevel6(creditLimit)
FROM
    customers
ORDER BY customerName;  
题目的sql

------------关于实例的sql数据库文档 -- 留言发邮箱

以上是关于存储过程的主要内容,如果未能解决你的问题,请参考以下文章

Java调用SQL Server的存储过程详解(转)

如何将 r ggplot 图存储为 html 代码片段

sql 这些代码片段将演示如何逐步使用PolyBase。你应该有一个blob存储和存储秘密方便

从Oracle存储过程Oracle 11g发送邮件

mybatis 存储过程

Sublime Text自定制代码片段(Code Snippets)