zoukankan      html  css  js  c++  java
  • 12 MySQL存储过程与函数

    存储过程和函数
        存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合.
        调用存储过程和函数可以简化应用开发人员的工作,减少数据在数据库和应用服务器之间的传输,提高数据处理的效率.
     
        存储过程和函数的区别在于:
            函数必须有返回值,而存储过程没有.
            存储过程的参数可以使用 IN,OUT,INOUT 类型;而函数的参数只能是IN类型.
         
        如果有函数从其他类型数据库迁移到MySQL就可能需要把函数改造成存储过程.
     
     
    存储过程和函数的相关操作
        首先确认是否有相应的权限.
            创建存储过程/函数 需要CREATE ROUTINE权限.
            修改/删除 存储过程/函数 需要ALTER ROUTINE权限.
            执行存储过程/函数 需要EXECUTE权限.
     
        1).创建/修改 存储过程或函数
            CREATE PROCEDURE sp_name ([proc_param[,...]])
                [characteristic …] 
                routine_body
     
            CREATE FUNCTION sp_name ([func_param[,...])
                RETURNS     type
                [characteristic …] 
                routine_body
     
     
                其中,
                proc_param :
                    [IN|OUT|INOUT] param_name type
     
                func_param :
                    param_name type
     
                type : any valid MySQL data type .
        
                characteristic :
                    LANGUAGE SQL
                    | [NOT] DETERMINISTIC
                    | {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
                    | SQL SECURITY {DEFINER | INVOKER}
                    | COMMENT 'string'
     
                routine_body :
                    valid SQL procedure statement or statements .
     
            
     
            ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
     
            characteristic :
                {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
                |SQL SECURITY {DEFINER|INVOKER}
                |COMMENT 'string'
     
            调用存储过程/函数,使用关键字CALL :
                CALL sp_name ([[parameter [,...]])
     
     
          注意: 存储过程/函数 中允许包含DDL ,也可以在存储过程中执行COMMIT/ROLLBACK 操作,还可以调用其他的过程/函数;
                    但是存储过程/函数 中不允许使用 LOAD DATA INFILE 语句.
     
     
               Demo :
                    DELIMITER $$
            
                    CREATE PROCEDURE film_in_stock (IN p_film_id INT , IN p_store_id INT , OUT p_film_count INT)
                    READS SQL DATA
                    BEGIN
                            SELECT inventory_id
                            FROM inventory
                            WHERE film_id = p_film_id
                            AND store_id = p_store_id
                            AND inventory_in_stock(inventory_id);
            
                            SELECT FOUND_ROWS() INTO p_film_count;
                    END $$
     
                    DELIMITER ;
     
                    CALL film_in_stock(2,2,@a);
            
                    SELECT @a ;
     
        注意 : 与视图的创建语法不同,存储过程/函数 的CREATE语法不支持使用 CREATE OR REPLACE对存储过程/函数进行修改.如需修改,可以执行ALTER语法.
     
     
     
        characteristic特征值的简单说明:
     
            1).LANGUAGE SQL
                说明下面过程的BODY是使用SQL语句编写(系统默认的),以后MySQL可能支持其它语言.
     
            2).[NOT] DETERMINISTIC:
                    目前还未被优化程序使用
                    DETERMINISTIC 每次输入一样输出也一样的程序
                    NOT DETERMINISTIC(系统默认).
     
            3).{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
                目前这些特征值只是提供给服务器,并未用来约束存储过程实际使用数据的情况.
                    CONTAINS SQL 表示子程序不包含读或者写数据的语句
                    NO SQL 表示子程序不包含SQL语句
                    READS SQL DATA 表示子程序包含读数据的语句
                    MODIFIES SQL DATA 表示子程序包含写数据的语句
                    默认值是 CONTAINS SQL
     
            4).SQL SECURITY {DEFINER | INVOKER}
                指定子程序 该用创建子程序者的权限来执行,还是使用调用者的权限来执行.默认值是DEFINER , 即使用创建者的权限执行.
     
            5).COMMENT 'string'
                存储过程/函数 的注释信息.
     
     
        
        2.删除存储过程/函数
            一次性只能删除一个存储过程/函数.需要有ALTER ROUTINE 权限.
            DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
     
     
        3.查看存储过程/函数
            1).查看存储过程/函数 的状态
                SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
     
            2).查看存储过程/函数 的定义
                SHOW CREATE {PROCEDURE|FUNCTION} sp_name
     
            3).通过查看information_schema.Routines 了解存储过程/函数 的信息
                包含名称,类型,语法,创建人等信息.
                demo:SELECT * FROM routines WHERE ROUTINE_NAME = 'film_in_stock' G
     
        
        4.变量的使用
     
            1).变量的定义
                DECLARE var_name [,...] type [DEFAULT value]
     
     
            2).变量的赋值
                SET var_name = expr [,var_name = expr] ...
     
                其中,expr 可以是字面量,函数返回值,SELECT 语句(要求结果有且只有一行)等.
                或者使用SELECT .. INTO .. 语句
                SELECT col_name[,..] INTO var_name[,..] table_expr
     
                 Demo :
     
                    DECLARE $$
     
            CREATE FUNCTION get_customer_balance( p_customer_id INT , p_effective_date DATETIME )
                RETURNS DECIMAL(5,2)
                DETERMINISTIC
                READS SQL DATA
            BEGIN
                    ...
                    DECLARE v_payments DECIMAL(5,2) ;
                    ...
                    SELECT IFNULL (SUM(payment,amount),0) INTO v_payments
                    FROM payment
                    WHERE payment.payment_date <= p_effective_date
                    AND payment.customer_id = p_customer_id ;
                    ...        
                    RETURN v_rentfees + v_overfees - v_payments ;
            END $$
            DECLARE ;
     
            CALL get_customer_balance(1,'2018-03-02 09:11:15') ;
                
     
     
        5.定义条件和处理
            1).条件的定义
                DECLARE condition_name CONDITION FOR condition_value
     
                其中,condition_value :
                    SQLSTATE [VALUE] sqlstate_value | mysql_error_code
     
            2).条件的处理
                DECLARE handler_type HANDLER FOR condition_value[,..] sp_statement
     
                handler_type :
                    CONTINUE | EXIT | UNDO(暂不支持)
     
                condition_value:
                    SQLSTATE [VALUE] sqlstate_value
                    |condition_name
                    |SQLWARNING
                    |NOT FOUND
                    |SQLEXCEPTION
                    |mysql_error_code
     
     
            demo:todo
     
     
     
        6.光标的使用 --就是游标
            可以使用游标对结果集进行循环处理
            1).声明光标
                DECLARE cursor_name CURSOR FOR select_statement
                    select_statement 中的SELECT语句 不能包含 INTO , 即不可以是SELECT .. INTO ..语句
                    SELECT 语句查询出来的列数 , 必须与FETCH游标中的接收数据的变量数 一致.     
     
            2).OPEN光标
                OPEN cursor_name
     
            3).FETCH光标
                FETCH cursor_name INTO var_name[,var_name,..]
     
            4).CLOSE光标
                CLOSE cursor_name
     
            Demo :  —— 需要注意 DECLARE 声明的顺序 : 变量 -> 游标 -> 条件处理 .
                DELIMITER $$
            
                CREATE PROCEDURE payment_stat()
                BEGIN
                    DECLARE i_staff_id INT ;
                    DECLARE d_amount DECIMAL(5,2);
                    DECLARE cur_payment CURSOR FOR SELECT staff_id,amount FROM payment ;
                    DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_payment ;
     
                    SET @x1 = 0 ;
                    SET @x2 = 0 ;
     
                    OPEN cur_payment ;
                    
                    REPEAT
                        FETCH cur_payment INTO i_staff_id,d_amount ;
                            IF i_staff_id = 2
                            THEN
                                SET @x1 = @x1 + d_amount ;
                            ELSE
                                SET @x2 = @x2 + d_amount ;
                            END IF ;
                    UNTIL 0 END REPEAT ;
     
                    CLOSE cur_payment ;
     
                END ;
                $$
     
                DELIMITER ;
     
                CALL payment_stat();
     
            注意:变量,条件,处理程序,游标都是通过DECLARE定义的,但是顺序是由先后要求的.
                变量和条件 必须声明在最前面,然后是游标的声明,最后才是处理程序的声明.
     
     
     
        7.流程控制
            1).IF语句
     
                IF search_condition
                    THEN statement_list
                [
                ELSEIF search_condition 
                    THEN statement_list
                ]
                [
                ELSE statement_list
                ]
                END IF
     
            2).CASE语句
                CASE case_value
                    WHEN when_value THEN
                         statement_list
                    [
                    WHEN when_value THEN
                         statement_list
                    ]
                        ...
                    [
                    ELSE 
                        statement_list
                    ]
                END CASE
     
               或者
                CASE WHEN search_condition THEN 
                        statement_list
                    [
                    WHEN search_condition THEN
                         statement_list
                    ]
                        ...
                    [
                    ELSE 
                        statement_list
                    ]
                END CASE
     
            Demo : 改写游标demo中IF语句
                
                CASE
                    WHEN i_staff_id = 2
                     THEN
                        SET @x1=@x1+d_amount ;
                    ELSE
                        SET @x2= @x2+d_amount ;
                END CASE ;
     
               或
                CASE i_staff_id
                    WHEN 2
                    THEN
                        SET @x1 = @x1 + d_amount ;
                    ELSE
                        SET @x2 = @x2 + d_amount ;
                END CASE ;
     
     
            3).LOOP 语句
                简单的循环,需要配合其他的语句定义来实现退出循环,通常使用LEAVE语句实现.
     
                [begin_label:] LOOP
                    statement_list
                END LOOP [end_label]
     
                如果没有退出循环语句,就是个死循环.
     
     
            4).LEAVE 语句
                从标注的流程中退出,通常和BEGIN..END / 循环 一起使用.
                Demo :
     
                    DELIMITER $$
     
                    CREATE PROCEDURE actor_insert()
                    BEGIN
                        SET @x = 0 ;
                        ins : LOOP
                            SET @x = @x+1;
                            IF @x=100
                            THEN
                                LEAVE ins ;
                            END IF ;
                            INSERT INTO actor(first_name,last_name)
                            VALUES('Test','201');
                        END LOOP ins ;
                    END ;
                    $$
     
                    DELIMITER ;
     
                    CALL actor_insert();
     
     
            5).ITERATE 语句
                必须用在循环中,表示跳过当前循环的剩下语句,进入下次循环.作用相当于Java中的continue.
     
                Demo:
                
                    DELIMITER $$
                    CREATE PROCEDURE actor_insert()
                    BEGIN
                        SET @x = 0 ;
                        ins : LOOP
                            SET @x = @x + 1;
                            IF @x = 10
                            THEN
                                LEAVE ins ;
                            ELSEIF mod(@x,2) = 0
                            THEN
                                ITERATE ins ;
                            END IF ;
                            INSERT INTO actor (actor_id , first_name,last_name)
                            VALUES(@x*10,'Test',@x);
                        END LOOP ins ;
                    END ;
                    $$
     
                    DELIMITER ;
                
                    CALL actor_insert() ;
     
            6).REPEAT 语句
                有条件的循环语句,相当于Java中的do_while
                不同的是REPEAT是满足条件时就退出循环,while是满足就执行.Repeat 和 do..while 一样,至少执行一次.
     
                    Demo参考游标的demo
     
     
            
            7).WHILE 语句
                [begin_label:] WHILE search_condition
                    DO statement_list
                END WHILE [end_label]
     
        
        总结:存储过程/函数的优势是可以将数据的处理放在数据库服务器上进行,避免将大量的结果集传输给客户端,减少数据传输,
                但是在数据库服务器上进行大量的复杂运算会占用服务器的cpu,造成数据库服务器的压力,
                所以存储过程/函数中不要进行大量的复杂运算,应该将这些运算操作分摊到应用服务器上执行.
         
  • 相关阅读:
    Lucene:(一)建立索引文件:2。建立索引文件(一)
    Lucene:(一)建立索引文件:2。建立索引文件(二)Segment文件
    92.外边距设置 Walker
    99.元素居中及样式重置 Walker
    94.外边距踩坑 Walker
    101.列表属性 Walker
    97.boxsizing属性 Walker
    98.溢出隐藏 Walker
    95.内边距设置 Walker
    96.内边距和边框踩坑 Walker
  • 原文地址:https://www.cnblogs.com/lmxxlm-123/p/11132056.html
Copyright © 2011-2022 走看看