很开心我今天又开设了一个新的专题,那就是数据库,俗话说不想当dba的程序员不是一个好前端。。。我这里不是mysql入门讲堂,讲的都是有一定基础的东西。
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 = 小明
我们把名为小明的学生学号给改了。。。那么这时候会在学生记录表也作出变更。
今天的讲解就到这里,相信大家觉得这些对比后台代码还是很简单的。