MySQL存储过程简介

存储过程简介

https://www.cnblogs.com/mark-chan/p/5384139.html

SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。

存储过程的优点:

(1).增强SQL语言的功能和灵活性:存储过程可以用控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

(2).标准组件式编程:存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。

(3).较快的执行速度:如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

(4).减少网络流量:针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织进存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大减少网络流量并降低了网络负载。

(5).作为一种安全机制来充分利用:通过对执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

 

 

MySQL的存储过程

 

存储过程是数据库的一个重要的功能,MySQL 5.0以前并不支持存储过程,这使得MySQL在应用上大打折扣。好在MySQL 5.0开始支持存储过程,这样即可以大大提高数据库的处理速度,同时也可以提高数据库编程的灵活性。

 

MySQL存储过程的创建

 

语法

 

CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体

 


DELIMITER //
  CREATE PROCEDURE myproc(OUT s int)
    BEGIN
      SELECT COUNT(*) INTO s FROM students;
    END
    //
DELIMITER ;

 

分隔符

 

MySQL默认以";"为分隔符,如果没有声明分割符,则编译器会把存储过程当成SQL语句进行处理,因此编译过程会报错,所以要事先用“DELIMITER //”声明当前段分隔符,让编译器把两个"//"之间的内容当做存储过程的代码,不会执行这些代码;“DELIMITER ;”的意为把分隔符还原。

 

注意: DELIMITER 后面不是一定要加//, 完全可以用其他字符代替, 只要确保在END之后也是用同样字符就行,例如用$$代替:
而且END之后的;可以有,也可以没有
DELIMITER $$
  CREATE PROCEDURE myproc(OUT s int)
    BEGIN
      SELECT COUNT(*) INTO s FROM students;
    END   // 可以写成END; 也可以写成END 
    $$
DELIMITER ;

 

 

参数

 

存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT:

 

  • IN参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
  • OUT:该值可在存储过程内部被改变,并可返回
  • INOUT:调用时指定,并且可被改变和返回

    过程体

    过程体的开始与结束使用BEGIN与END进行标识。下面的测试实例本人都在mysql的5.5版本测试全部通过.

  • IN参数例子
    drop procedure if exists in_param;
    
    delimiter $$
    create procedure in_param (in p_in int)
    begin
        select p_in ;       # 输出1
        set p_in = 2 ;      # 改变值
        select p_in ;       # 输出2
    end $$
    delimiter ;
    
    #调用
    set @p_in = 1;           # 初始p_in的值
    call in_param (@p_in);   # 会输出1,然后输出2
    select
        @p_in;               # 输出1

    以上可以看出,p_in虽然在存储过程中被修改,但并不影响初始@p_in的值,所以in类型相当于java中的值传递.
    
    
    OUT参数例子
    drop procedure if exists out_param;
    
    #存储过程out参数
    delimiter //
      create procedure out_param(out p_out int)
        begin
          select p_out;  # 第一次要输出输出p_out,没有设置值, 所以伪null, 这里千万不要以为要输出的是参数p_out, 因为它的类型是out,所以要改变值才行
          set p_out=2;
          select p_out;  # 第二次输出2, 因为改变了值, 就算这里之前把它设为set p_out=1, 也会输出1,因为只要改变就可以,而且影响全局的
        end;
        //
    delimiter ;
    #调用
    set @p_out=1;
    call out_param(@p_out);  # 输出null, 然后2
    select @p_out;           # 输出2
    以上可以看出,p_out在存储过程中被修改,同时影响了初始@p_out的值,所以out类型相当于java中的引用传递(地址传递).
    
    
    INOUT参数例子
    drop procedure if exists inout_param;
    
    #存储过程inout参数
    delimiter //
      create procedure inout_param(inout p_inout int)
      begin
        select p_inout;   #输出1
        set p_inout = 2;  
        select p_inout;   #输出2
        end //
    delimiter ;
    
    set @p_inout = 1;
    call inout_param(@p_inout);
    select @p_inout;     #在存储过程中改变了值,所以这里输出是2

    变量

    语法:DECLARE 变量名1[,变量名2...] 数据类型 [默认值];

    数据类型为MySQL的数据类型:

    数值类型

    image

    日期和时间类型

    image

    字符串类型

    image

    变量赋值

    语法:SET 变量名 = 变量值 [,变量名= 变量值 ...]

    用户变量

    用户变量一般以@开头

    注意:滥用用户变量会导致程序难以理解及管理

  • select 'hello world' into @x;
    select @x;   # 输出hello world
    set @y='goodbye cruel world';
    select @y;   # 输出goodbye cruel world
    set @z=1+2+3;
    select @z;   # 输出6
    drop procedure if exists greetworld;
    create procedure greetworld() select concat(@greeting,' world');
    set @greeting='hello';
    call greetworld();  # 输出hello world
    drop procedure if exists p1;
    drop procedure if exists p2;
    create procedure p1() set @last_proc='p1';
    create procedure p2() select concat('last procedure was ',@last_proc);
    call p1();  
    call p2(); #输出last procedure was p1
    • 注释
    • MySQL存储过程可使用两种风格的注释:

    • #号:#,该风格一般用于单行注释
    • C风格:/*   code  */ 一般用于多行注释

      MySQL存储过程的调用

      用call和你过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数。

    • 如上面 call inout_param(@p_inout);  call p1();  call p2();

      MySQL存储过程的查询

    • 假设目前存在一个数据库名字是test,里面有一个表plugin,数据模型如下图, (其中的数据是随便添加的,没有任何的实际意义, 仅作测试使用)
          •  下面是个人在测试用的实例, 亲测都可以通过

            use test;
            drop procedure if exists mysql_data;
            
            delimiter $$
            create procedure mysql_data(inout param int)
            begin
              #select test.plugin.sender from test.plugin limit 2; # 有数据的话就输出
              #select sender from test.plugin limit 2; # 比上面的写法简介点
              select * from information_schema.columns where table_name = 'plugin' and column_name = 'sender' limit 2;
            # 这种写法是要判断是否存在指定的列名, information_scheme是mysql的系统表,无需建立,读者可以在自己mysql上查看这个表的具体内容
            end $$ delimiter; set @param = 45; call mysql_data(@param);

            show create procedure test.mysql_data; #可以查看存储过程的详细信息
            use test;
            drop procedure if exists mysql_data;
            delimiter $$
            create procedure mysql_data()
            begin
                if not exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'cx1') then
                    alter table test.plugin add column cx1 varchar(100); # 在plugin表增加一列cx1
                end if;
                if not exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'cx2') then
                    alter table test.plugin add column cx2 varchar(100) after cx1; # 在plugin表的列名为cx1后面增加一列cx2
                end if;
                if not exists (select * from plugin where id = '1') then
                    insert into plugin(id, sender, cx2) values (1, 'sendertest', 'cx2test'); # 如果id为1的不存在,就增加一条数据,否则不增加(id是主键, duplicate key error)
                end if;
             
            end $$ 
            delimiter;
            call mysql_data();

            use test;
            drop procedure if exists mysql_data;
            
            delimiter $$
            create procedure mysql_data()
            begin
                if exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'link') then
                    alter table test.plugin modify column link varchar(120); # 修改plugin表中link的字段长度
                end if;
                if exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'hidden') then
                    alter table test.plugin modify column hidden char(110); # 修改plugin表中hidden的字段类型或者长度
                end if;
                if not exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'cx1') then
                    alter table test.plugin add column cx1 varchar(100) after hidden; # 在plugin表的列名为cx1后面增加一列cx1
                end if;
                if not exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'cx2') then
                    alter table test.plugin change cx1 cx2 varchar(150); # 修改plugin表中cx1的名字为cx2, 同时更改长度
                end if;
                if exists (select * from information_schema.columns where table_name = 'plugin' and column_name = 'cx2') then
                    alter table test.plugin drop column cx2; # 删除plugin表中名字为cx2的列
                end if;
            end $$
            delimiter;
            call mysql_data();
            drop procedure if exists mysql_data;
            delimiter $$
            create procedure mysql_data(in p_in int(11), out p_out varchar(100))
            begin
                declare pluginid int default 0;
                select p_out;        # 输出null
                
               select id into pluginid
                from plugin
                where plugin.id = p_in;
                
                if pluginid <= 100 then
                    set p_out = 'lees than 100';
                elseif (pluginid <= 110 and pluginid > 100) then #这里elseif 必须写在一起,不能写成else if, 下同
                     set p_out = 'less than 110';
                elseif (pluginid <= 120 and pluginid > 110) then
                     set p_out = 'less than 120';
            else
            set p_out = 'unknow';
            end if;
            select p_out; # 输出less than 110 end $$ delimiter ; set @p_in = 101; set @p_out = 'init'; call mysql_data(@p_in, @p_out); 
            drop procedure if exists mysql_data;
            delimiter $$
            create procedure mysql_data()
            begin   
                declare para varchar(10);
                set para = 'good'; # 假设数据库中值存在为good
            
                select id
                from plugin
                order by
                   #case when status is not null then id end desc,
                    #case when status <> para then id end asc,
                    case when status = para then id end desc,
                    case when status is null then id end asc;
            end $$
            
            delimiter ;
            call mysql_data(); 
            drop procedure if exists mysql_data;
            delimiter $$
            create procedure mysql_data(out times char(50))
            begin
            
                declare i int (11);
                declare types varchar(50);
            
                set i = 1;
                while i < 10 do
                    if (i > 1 and i < 5) then
                        set times = date_format(now(), '%Y/%m/%d-%H:%i:%s');
                        set types = 'aaa';
                    elseif ((i mod 2) = 4) then
                        set times = date_format(now(), '%Y-%m-%d-%H:%i:%s');
                        set types = 'bbb';
                    else
                        set times = date_format(now(), '%Y%m%d-%H:%i:%s');
                        set types = 'ccc';
                    end if;
                set i = i + 1;
                end while;    
            end $$
            delimiter ;
            set @times = '';
            call mysql_data(@times);
            select @times;  // 20180329-15:00:09
            devices 表格的模型在这里就不给出了, 这里主要是学习存储过程的用法和mysql对string/int的处理, 如使用cast方法相互转换、拼接concat用法、循环while、判断if等的用法

            drop
            procedure if exists insert_devices; delimiter $$ create procedure insert_devices() begin declare i int (11); declare ip int (11); declare deviceid varchar(50); declare tvserialnumber varchar(20); declare tvuniqueid varchar(255); declare tvip varchar(15); declare types varchar(50); declare firmId varchar(100); declare times varchar(30); set i = 1 ; while i < 150 do set deviceid = '6463g092105542aa2c5a21e'; set tvserialnumber = '6463g092105'; set tvuniqueid = '6463g092105542aa2c5a21e'; set deviceid = concat(cast(i as char), deviceid); set tvserialnumber = concat(cast(i as char), tvserialnumber); set tvuniqueid = concat(cast(i as char), tvuniqueid); set ip = i + 40; set tvip = concat('192.168.0.', ip); if ((i mod 2) = 2) then set types = '2016 MS'; elseif ((i mod 2) = 4) then set types = '2016 MS'; else set types = '2016 SS'; end if; if (i < 10) then set firmId = concat('TPM153', cast(i as char), 'HE.5.249.5.065'); elseif (i > 10 and i < 100) then # 注意这里一定要写成elseif, 千万不要写成else if, 要连在一起写 set firmId = concat('TPM1531HE.5.249.5.0', cast(i as char)); elseif (i > 100) then set firmId = concat('TPM1531HE.5.', cast(i as char), '.5.065'); end if; set times = date_format(now(), '%Y%m%d%H%i%s'); if not exists (select * from devices where id = deviceid) then insert into smartinstall.devices values ( deviceid, 'TV 28 Mar 2018 10:18:05', '49HFl7011T/12', tvserialnumber, concat(cast(i as char), cast(i as char)), '54:2a:a2:c5:a2:1e', tvip, '800000000000000f6921', types, 'offline', tvuniqueid, null, null, '{\"old\":\"Unknown\",\"new\":\"Unknown\"}', null,null,null,null,null, '27/03/2018:10:47', firmId, null, null, 'black', 'black', '2018/03/28-10:18:05', null, times, 'Upgrade', 'ST', null,null,null,null,null,null,null ) ; end if; set i = i + 1 ; end while ; end $$ delimiter ; call insert_devices();

             

            drop procedure if exists insert_device;
            delimiter $$
            create procedure insert_device()
            begin
                    declare i int (11);
                    declare ip int (11);
                    declare deviceid varchar(50);
                    declare tvserialnumber varchar(20);
                    declare tvmacaddress varchar(17);
                    declare tvuniqueid varchar(255);
                    declare tvip varchar(15);
                    declare types varchar(50);
                    declare firmId varchar(100);
                    declare times varchar(30);
                    set i = 11 ;
                    set deviceid = '6463g092105542aa2c5a21e';
                    set tvserialnumber = '6463g092105';
                   set tvmacaddress = ':2a:a2:c5:a2:1e';
                    set tvuniqueid = '6463g092105542aa2c5a21e';
            
                    set deviceid = concat(cast(i as char), deviceid);
                    set tvserialnumber = concat(cast(i as char), tvserialnumber);
                    set tvmacaddress = concat(cast(i as char), tvmacaddress);
                    set tvuniqueid = concat(cast(i as char), tvuniqueid);
                    set ip = i + 40;
                    set tvip = concat('192.168.0.', ip);
                    if ((i mod 2) = 2) then
                        set types = '2016 MS';
                    elseif ((i mod 2) = 4) then
                        set types = '2016 MS';
                    else
                        set types = '2016 SS';
                    end if;
                    
                    if (i < 10) then
                        set firmId = concat('TPM153', cast(i as char), 'HE.5.249.5.065');
                    elseif (i > 10 and i < 100) then
                        set firmId = concat('TPM1531HE.5.249.5.0', cast(i as char));
                    elseif (i > 100) then
                        set firmId = concat('TPM1531HE.5.', cast(i as char), '.5.065');
                    end if;
                    
                    set times = date_format(now(), '%Y%m%d%H%i%s');
                if not exists (select * from devices where id = deviceid) then 
                        
                        insert into smartinstall.devices
                        values
                        (
                            deviceid,
                            'TV 28 Mar 2018 10:18:05',
                            '49HFl7011T/12',
                            tvserialnumber,
                            concat(cast(i as char), cast(i as char)),
                            '54:2a:a2:c5:a2:1e',
                            tvip,
                            '800000000000000f6921',
                            types,
                            'offline',
                            tvuniqueid,
                            null,
                            null,
                            '{\"old\":\"Unknown\",\"new\":\"Unknown\"}',
                            null,null,null,null,null,
                            '27/03/2018:10:47',
                            firmId,
                            null,
                            null,
                            'black',
                            'black',
                            '2018/03/28-10:18:05',
                            null,
                            times,
                            'Upgrade',
                            'ST',
                            null,null,null,null,null,null,null
                        ) ;            
                    end if;
            end$$
            delimiter ;
            
            create event
            if not exists e_insert_device on schedule every 3 second on completion preserve do
                call insert_device();

            参考网址: https://blog.csdn.net/qq_26562641/article/details/53301407

             

  • MySQL存储过程的修改

    ALTER PROCEDURE 更改用CREATE PROCEDURE 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。

  • ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
    characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
    | SQL SECURITY { DEFINER | INVOKER }
    | COMMENT 'string'
    sp_name参数表示存储过程或函数的名称; characteristic参数指定存储函数的特性。 CONTAINS SQL表示子程序包含SQL语句,但不包含读或写数据的语句; NO SQL表示子程序中不包含SQL语句; READS SQL DATA表示子程序中包含读数据的语句; MODIFIES SQL DATA表示子程序中包含写数据的语句。 SQL SECURITY { DEFINER | INVOKER }指明谁有权限来执行,DEFINER表示只有定义者自己才能够执行;INVOKER表示调用者可以执行。 COMMENT 'string'是注释信息。

    后续会接着写的....

posted on 2018-03-25 17:17  努力做一个伪程序员  阅读(448)  评论(0编辑  收藏  举报

导航