zoukankan      html  css  js  c++  java
  • mysql存储过程语法与实例

    大纲:

    1. 创建、删除、调用。
    2. 声明变量、变量赋值、存储过程的入参
    3. 声明游标
    4. 声明异常处理器
    5. 判断
    6. 循环
    7. 使用心得
    8. mybatis调用存储过程

     

    一、创建、删除、调用

    • 创建
      DELIMITER $$ #修改分隔符
      CREATE PROCEDURE test(IN pname VARCHAR(50)) #括号里是入参。
        BEGIN
          select pname; #存储过程中的语句用;结尾
        END$$ #存储过程本身用修改后的分隔符$$结尾
      DELIMITER ; ##还原分隔符

      begin、end之间是存储的执行的代码块。

       tips:mysql不支持匿名块(没有create procedure,直接写begin、end之间的内容),因此msql的代码块只能放在存储过程,自定义函数,触发器中。

    • 删除
      DROP PROCEDURE IF EXISTS test; #存储过程

      和表一样建立前确保数据库中没有同名存储过程。

    • 调用
      CALL test('xx');

      调用用call命令、这里参数传一个字符串进去、调用后显示xx。

    二、声明变量、变量赋值、存储过程的入参

    • declare声明变量
    • set是直接赋值(可以用 '=' 号赋值,也可以用 ':=' 赋值,本文例子中都是用 '=' 赋值的。但之后的学习中发现用这种 ':=' 方式赋值更规范一些。)
    • select是将查询的结果进行赋值
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test(IN pname VARCHAR(50))
        BEGIN
          DECLARE prefix VARCHAR(20); #声明变量
          set prefix = 'nihao:'; #select 'nihenhao:' into prefix; 赋值
          select concat(prefix,pname); #concat函数:拼接2个字符串
        END$$
      DELIMITER ;
      CALL test('xx');:赋值方式有2种、根据需求选择。
    •  创建存储过程的时候已经提到了,存储过程可以有入参IN,也可以有出参OUT,还可以有出入参INOUT。IN类型只能作为传入参数使用,OUT只能作为传出参数使用,只有INOUT既可以传入存储过程又能传出来。
      drop PROCEDURE test;
      DELIMITER $$
      CREATE PROCEDURE test( IN people VARCHAR(8), OUT name VARCHAR(8),INOUT age INT )
      BEGIN
          IF people = 'man'
          THEN SET name := 'xiaoming';
            SET age :=age+1;
          ELSE SET name := 'xiaohong';
            SET age :=age+10;
          END IF;
        END $$
      
      set @people = 'man'; #@var_name这样的写法是声明一个用户变量,只有在本次连接的客户端中有效。这里声明了3个变量people、name、age
      set @name = null;
      set @age = 6;
      call test(@people,@name,@age);
      SELECT @people,@name,@age from dual; #结果:man     xiaoming     7

    三、声明游标

    • 准备一个测试表
      TRUNCATE names;
      create table names
      (
        name VARCHAR(20),
        age int
      );
      INSERT into names VALUES ('lby',45);
      INSERT into names VALUES ('lala',23);
    • 游标可以理解为是一个带指针的结果集。
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test()
        BEGIN
          DECLARE name VARCHAR(20);
          DECLARE age int;
          DECLARE temp VARCHAR(50);
          DECLARE c1 CURSOR FOR select * from names; #声明游标
          OPEN c1; #使用游标前打开游标
          FETCH c1 INTO name,age; #将游标中的第一行依次付给name,age(name=lby,age=45)。tips:游标列数和变量数要相同。
          set temp = CONCAT(name,age);
          FETCH c1 INTO name,age; #第一次fetch后指针下移动,赋值第二行给name,age(name=lala,age=23)。
          CLOSE c1; #使用游标后关闭游标
          set temp = CONCAT(temp,CONCAT(name,age));
          SELECT temp from dual; #lby45lala23
        END$$
      DELIMITER ;
      CALL test();

    四、声明异常处理器

    • 当sql执行时报错时会报出相应的sqlstate,根据不同的sqlstate我们可以给出不同的处理。--附一个sqlstate的详解:blog.csdn.net/u014653854/article/details/78986780
    • 处理器有2种:exit、continue。
      TRUNCATE names; #清空names表使fetch报错SQLSTATE'02000'
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test()
        BEGIN
          declare age int default 0 ;
          declare name VARCHAR(20) default 0 ;
          declare flag int default 0;
          DECLARE c1 CURSOR FOR select * from names;
          declare CONTINUE HANDLER FOR SQLSTATE '02000' SET flag = 111;  # continue handler 检测报错为02000的时候 将flag设为111,存储过程继续执行,如果换为exit handler在行为完处理语句set flag=111后直接退出存储过程。
          OPEN c1;
          FETCH c1 into name,age; #当执行这句时会报错sqlstate:02000 ,continue handler触发set flag= 111,继续执行后面的代码。
          CLOSE c1;
          select flag; #111
        END$$
      DELIMITER ;
      CALL ifpay_ccpay.test();

    五、判断

    • if判断
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test(in age int)
        BEGIN
          declare flag VARCHAR(20);
          IF age = 1 THEN SET flag = '';
          ELSEIF age = 2 THEN SET flag = '';
          ELSE SET flag = 'I DONT KNOW';
          END IF; #结束标志
          select flag; #二
        END$$
      DELIMITER ;
      CALL ifpay_ccpay.test(2);

    六、循环

    循环有三种

    • while循环
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test()
        BEGIN
          DECLARE age int DEFAULT 0;
          mywhile:
          WHILE age < 5 #条件,
          DO
            set age = age+1; #do与endwhile之间是循环内容
          END WHILE ;
          SELECT age; #5
        END$$
      DELIMITER ;
      CALL test();
    • repeat循环
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test()
        BEGIN
          DECLARE age int DEFAULT 0;
          mywhile:
          repeat
           set age = age+1; #循环体
          UNTIL age>3 END REPEAT ; #条件
          SELECT age; #4
        END$$
      DELIMITER ;
      CALL test();
    • loop循环
      DROP PROCEDURE IF EXISTS test;
      DELIMITER $$
      CREATE PROCEDURE test()
        myproc: #存储过程的label
        BEGIN
          DECLARE age int DEFAULT 0;
          DECLARE count int DEFAULT 10;
          myloop: #loop的label
          LOOP
            set age = age +1;
            IF age < 5 then
              ITERATE myloop; #忽略后面代码继续执行。(continue)
            END IF;
            set count = count - 1; 
            SELECT 'haha'; 
            LEAVE myloop; #离开循环。(break) leave也可直接用于存储过程本身myproc,如果这里换成myproc,则显示haha
          END LOOP;
          SELECT age,count; #5    9
        END$$
      DELIMITER ;
      CALL test();

       代码中有3个概念:label、iterate、leave

       label:名称标签,while、repeat、loop循环或者 存储过程本身begin关键字前面都可以加一个名称标签。  

       iterate:用于循环、继续当前循环,相当于java循环中的continue。

       leave:1.用于循环、离开当前循环,相当于java循环中的break。

            2.也可用于存过过程本身,直接离开存过过程。

    循环小结:1.while repeat区别在于:while 先判断循环条件再循环,repeat 线循环后判断。

         2.loop没有结束条件,需要手动退出。

         3.iterate、leave也可以用于while、repeat。

    七、使用心得

    1. 存储过程中慎用delete语句。
    2. 存储过程适合一些有规律的数据操作,比如根据一些业务规则初始化一些数据。
    3. 尽量不要用它代替简单的业务sql,因为存储过程的维护、迁移、易读性都不如直接写在代码中好。

    八、mybatis调用存储过程

    调用方式参考我另一篇文章:mybatis调用存储过程

  • 相关阅读:
    DataTablez转List对象效率慢的问题.
    Oracle 删除重复数据
    1.layui 添加旋转等待, 2.div里面加载HTML页面
    layui-table JSON.stringify()序列化出来的不同行数据类型错误.导致后台转成表格的时候出错.(常用)
    0基础学MVC课程
    构造函数的执行顺序
    html控件自动点 “加号”添加 多个附件
    C#委托之个人理解 转自 loose_went
    一步一步学Linq to sql系列文章 转lovecherry
    使用AOP 使C#代码更清晰 转yanghua_kobe
  • 原文地址:https://www.cnblogs.com/liuboyuan/p/9375882.html
Copyright © 2011-2022 走看看