zoukankan      html  css  js  c++  java
  • 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'是注释信息。

      后续会接着写的....

  • 相关阅读:
    vue+elementUI实现权限的部门管理
    vue+elementUI实现权限的部门管理
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    20 种最奇怪的编程语言
    WinForm导出文件
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/xumBlog/p/8645233.html
Copyright © 2011-2022 走看看