存储过程与触发器

很开心我今天又开设了一个新的专题,那就是数据库,俗话说不想当dba的程序员不是一个好前端。。。我这里不是mysql入门讲堂,讲的都是有一定基础的东西。

1 存储过程

话不多说,咱们举个例子简单了解下。


存储过程与触发器_第1张图片

这是一张学生表,含有3个数据。

DROP PROCEDURE if EXISTS Proc;

DELIMITER //
CREATE PROCEDURE Proc()
BEGIN
   SELECT * FROM student;
END// 
DELIMITER ;

CALL Proc();

我们通过CREATE PROCEDURE创建了一个存储过程Proc,语句是查询student表内容,调用通过call,返回内容就是表的数据。

DROP PROCEDURE if EXISTS Proc;

DELIMITER //
CREATE PROCEDURE Proc(IN id INT)
BEGIN
   SELECT * FROM student WHERE age > id;
END// 
DELIMITER ;

CALL Proc(23);

我们将这个存储过程改为了查询年龄大雨23岁的。

其实到这里大概也知道了,存储过程到底是干嘛的,其实就是编写一个函数让我们可以更轻松的拿取我们想要的数据。

DROP PROCEDURE if EXISTS Proc;

DELIMITER //
CREATE PROCEDURE Proc(IN id INT ,OUT count INT)
BEGIN
  SELECT count(*) into count FROM student WHERE age > id;
END// 
DELIMITER ;

CALL Proc(21,@count);
select @count;

这个存储过程里面️个参数,一个输出,一个输入,注意输出用@,count最后代表的是大于21的人个数。

我们现在有个需求就是往这个student表里添加10个学生,我们这次是使用存储过程来做的。

DELIMITER $$
DROP PROCEDURE IF EXISTS `addStudent` $$
CREATE PROCEDURE addStudent( IN studentCount INT ) 
BEGIN 
    DECLARE i INT DEFAULT 0;                  -- 计数器
    DECLARE returnMsg VARCHAR(50) DEFAULT '';   -- 返回值信息
    DECLARE rowCount int DEFAULT 0;             -- 操作sql的时候影响行数
    
      outer_label:BEGIN
      START TRANSACTION;
      WHILE i < studentCount DO
        SET i=i+1;
        INSERT INTO `student`   (`name`,`age`) VALUES ('****',i+1);
        SELECT row_count() INTO rowCount;
        IF rowCount<=0 THEN
            LEAVE outer_label;            
        END IF;                 
      END WHILE;

      END outer_label;  -- 只要是在outer_label代码块内 任意位置 Leave outer_label,那么Leave后的代码将不再执行 

      IF i=studentCount THEN
        COMMIT;
        SET returnMsg = i;
          ELSE
        ROLLBACK;
        SET returnMsg = 'error';
         END IF;
      SELECT returnMsg;
   
END $$
DELIMITER ;

其实这就是在mysql里面写了一回js代码,注意while和if的用法即可。通过addStudent(10)插入10条数据。

上面的例子比较综合,咱们以一个简单例子结尾。

DELIMITER //  
CREATE PROCEDURE proc1 (IN parameter1 INTEGER)   
BEGIN   
    DECLARE variable1 CHAR(10);   
    IF parameter1 = 17 THEN   
        SET variable1 = 'birds';   
        ELSE 
        SET variable1 = 'beasts';   
    END IF;   
INSERT INTO table1 VALUES (variable1);  
END //  
DELIMITER ;

在存储过程间传递全局范围的用户变量

1.  mysql> CREATE PROCEDURE p1()   SET @last_procedure='p1';  
2.  mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_procedure);  
3.  mysql> CALL p1( );  
4.  mysql> CALL p2( );  
5.  +-----------------------------------------------+  
6.  | CONCAT('Last procedure was ',@last_proc       |  
7.  +-----------------------------------------------+  
8.  | Last procedure was p1                         |  
9.  +-----------------------------------------------+

查看当前数据库的存储过程:

show procedure status;

来看这段代码

DROP PROCEDURE IF EXISTS proc3;
DELIMITER //  
CREATE PROCEDURE proc3()  
  begin 
    declare x1 varchar(5) default 'outer';  
    begin 
    declare x1 varchar(5) default 'inner';  
    select x1 as qwe;
    end;  
    select x1 as qwe;
  end //  
DELIMITER ;

CALL proc3();

此时显示的是x1=inner...

一个简单的流程控制的存储过程

drop procedure if exists proc4;
DELIMITER //  
CREATE PROCEDURE proc4 (in parameter INT)  
  begin 
    declare var int;  
    declare asd int;
    set var=parameter+1;  
    case var  
        when 0 then  
          set asd = 11; 
          select asd as qwe;  
        when 1 then 
          set asd = 12;   
          select asd as qwe;  
        else   
          set asd = 13; 
          select asd as qwe;  
    end case;  
  end //  
DELIMITER ;

call proc4(0);

存储过程的概念其实很简单,但是想要写出很好的存储过程需要一定的coding skill,大家可以慢慢学习。。

2 触发器

触发器是一个特殊的存储过程,不同的是存储过程要用CALL来调用,而触发器不需要使用CALL,也不需要手工启动,只要当一个预定义的事件发生的时候,就会被MYSQL自动调用。

drop trigger ins_sum
SET @qqq=0;
CREATE TABLE account2(acct_num INT ,amount INT);
CREATE TRIGGER ins_sum BEFORE INSERT ON account2
FOR EACH ROW SET @qqq=@qqq+new.amount;

INSERT INTO account2 VALUES(1,3),(2,5);
SELECT @qqq as qwe;

这个触发器的意思是说每次往account2里面插入数据时,更改@qqq的值,注意new是值的插入的那一行。

触发器中new和old的作用

  • 针对update操作,new表示的是更新后的值,old表示的是原来的数据。
  • 针对insert操作,new表示的是插入的值。
  • 针对delete操作,old表示的是删除后的值。
    本例子是insert,操作是before。

关于mysql变量定义可以看这篇文章.

创建有多个执行语句的触发器,语法如下:

DELIMITER |
 
CREATE TRIGGER testref BEFORE INSERT ON test1
  FOR EACH ROW BEGIN
    INSERT INTO test2 SET a2 = NEW.a1;
    DELETE FROM test3 WHERE a3 = NEW.a1;  
    UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
  END
|

一次插入操作导致3个表发生变化。。。

我们来考虑一个更为实际的问题,有一张表记录着我进货水果详细,还有一张表是对我进货水果种类的统计,此时我进货了10个apple回来,那么这2张表该如何变化。

CREATE TRIGGER FRUIT BEFORE INSERT ON FRUIT_DETAIL
     FOR EACH ROW BEGIN
              UPDATE FRUIT_STATISTIC SET COUNT = COUNT + NEW.IN_NUM         
              WHERE FRUIT_NAME = NEW.NAME
END

上面这个就表示了这个过程。

下面这个例子表示了一个删除的触发器

-- 删除触发器
mysql> delimiter $$
mysql> create trigger tab1_delete_after after delete
    -> on tab1 for each rows
    -> BEGIN
    ->   delete from tab2 where tab2_id = old.tab1_id;
    -> END
    -> $$
Query OK, 0 rows affected (0.01 sec)

delete from tab1 where tab1_id = 12
mysql> delimiter ;

注意这里我们用的是old,删除时就使用old。

下面这个例子表示了一个更改的触发器

-- 更新学生表的同时也更新记录表
delimiter $$
mysql> create trigger student1_update_after after update
    -> on student1 for each row
    -> BEGIN
    ->  if new.student_id != old.student_id then
    ->   update update_student1 set student_id = new.student_id, update_date = now()
    ->   where student_id = old.student_id;
    ->  end if;
    -> END
    -> $$
delimiter ;

update student1 set student_id = 23 where name = 小明

我们把名为小明的学生学号给改了。。。那么这时候会在学生记录表也作出变更。

今天的讲解就到这里,相信大家觉得这些对比后台代码还是很简单的。

你可能感兴趣的:(存储过程与触发器)