CONTEND
二、mysql存儲過程procedure和函數function
一、MySQL觸發器Triggers
1.1 觸發器簡介
觸發器( trigger )是一個特殊的存儲過程,它的執行不是由程序調用,也不是手工啓動,而是由事件來觸發,比如當對一個表進行操作( insert , delete,update )時就會激活它執行。觸發器經常用於加強數據的完整性約束和業務規則等。
例如,當學生表中增加了一個學生的信息時,學生的總數就應該同時改變。因此可以針對學生表創建一個觸發器,每次增加一個學生記錄時,就執行 一次學生總數的計算操作,從而保證學生總數與記錄數的一致性。
1.2 創建觸發器
(1)先舉個簡單的示例幫助我們理解這個觸發器:創建兩個表student和student_total,表student每次插入一個學生數據或刪除學生數據,student_total作相應的修改:
--創建表並插入數據
create table student ( id int unsigned auto_increment primary key not null, name varchar(50) not null, age int not null default 18);
create table student_total ( total_num int );
insert into student_total value(0);
--下面開始創建觸發器,針對insert操作
delimiter $
create trigger stu_insert after insert on student for each row begin update student_total set total_num=total_num+1; end$
--針對delete操作
create trigger stu_delete after delete on student for each row begin update student_total set total_num=total_num-1; end$
--把分隔符修改回來然後開始插入,刪除測試下
delimiter ;
insert into student(name) values ('alice'),('bob');
select * from student_total;
+-----------+
| total_num |
+-----------+
| 2 |
+-----------+
delete from student where name='alice';
select * from student_total;
+-----------+
| total_num |
+-----------+
| 1 |
+-----------+
(2) 進階一下,創建tab1和tab2,創建觸發器(insert、delete和update)接着插入、刪除更新數據試試
create table tab1(id int auto_increment primary key,name varchar(50) not null, sex enum('male','female') default 'male' , age int not null);
create table tab2( id int primary key auto_increment, name varchar(50), salary double(10,2) default 5000);
這邊要強調一點,當你刪除或者更新的時候,後面一定跟的是主鍵。比如id就是主鍵,否則會造成一些問題如誤刪數據等,這個要謹慎! (還有刪除後面跟的是主鍵就可以了,但更新的話要設置所有的字段都更新哦)
create trigger tab1_insert after insert on tab1 for each row begin insert into tab2 values (new.id,new.name,5000); end$
create trigger tab1_delete after delete on tab1 for each row begin delete from tab2 where id=old.id; end$
create trigger tab1_update after update on tab1 for each row begin update tab2 set id=new.id,name=new.name where id=old.id; end$
insert into tab1 values (1,'alice','male',19),(2,'bob','male',20),(4,'Gwen','female',23);
select * from tab1;
+----+-------+--------+-----+
| id | name | sex | age |
+----+-------+--------+-----+
| 1 | alice | male | 19 |
| 2 | bob | male | 20 |
| 4 | Gwen | female | 23 |
+----+-------+--------+-----+
select * from tab2;
+----+-------+---------+
| id | name | salary |
+----+-------+---------+
| 1 | alice | 5000.00 |
| 2 | bob | 5000.00 |
| 4 | Gwen | 5000.00 |
+----+-------+---------+
delete from tab1 where id=4;
select * from tab2;
+----+-------+---------+
| id | name | salary |
+----+-------+---------+
| 1 | alice | 5000.00 |
| 2 | bob | 5000.00 |
+----+-------+---------+
update tab1 set name='aliceCC' where id =1;
select * from tab2;
+----+---------+---------+
| id | name | salary |
+----+---------+---------+
| 1 | aliceCC | 5000.00 |
| 2 | bob | 5000.00 |
+----+---------+---------+
(3)再來一個示例,幫助我們再進一步去理解這個觸發器。創建 t1和t2 表,如下:
create table t1 (id int auto_increment primary key, name varchar(50), salary double(10,2));
create table t2(
-> total_num int not null,
-> total_salary double(10,2));
insert into t2 values(0,0);
select * from t2;
+-----------+--------------+
| total_num | total_salary |
+-----------+--------------+
| 0 | 0.00 |
+-----------+--------------+
delimiter $
create trigger total_num_salary after insert on t1 for each row begin update t2 set total_num=total_num+1,total_salary=total_salary+new.salary;end$
create trigger total_num_salary2 after delete on t1 for each row begin update t2 set total_num=total_num-1,total_salary=total_salary-old.salary; end$
delimiter ;
insert into t1(name,salary) values
-> ('alice',6000),
-> ('bob',6500),
-> ('jack',10000);
select * from t2;
+-----------+--------------+
| total_num | total_salary |
+-----------+--------------+
| 3 | 22500.00 |
+-----------+--------------+
delete from t1 where name='jack';
select * from t2;
+-----------+--------------+
| total_num | total_salary |
+-----------+--------------+
| 2 | 12500.00 |
+-----------+--------------+
1.3 觸發器的管理(查看,刪除)
這個比較簡單,記住語法格式就好了。
- 查看操作
- 刪除操作
二、mysql存儲過程procedure和函數function
2.1 procedure和function概述:
存儲過程和函數是事先經過編譯並存儲在數據庫中的一段SQL語句的集合。
存儲過程和函數的區別:
- 函數必須有返回值,而存儲過程沒有。
- 存儲過程的參數可以是IN、OUT、INOUT類型,函數的參數只能是IN
優點:
- 存儲過程只在創建時進行編譯;而SQL語句每執行一次就編譯一次,所以使用存儲過程可以提高數據庫執行速度。
- 簡化複雜操作,結合事務一起封裝。
- 複用性好
- 安全性高,可指定存儲過程的使用權。
說明:
- 併發量少的情況下,很少使用存儲過程。
- 併發量高的情況下,爲了提高效率,用存儲過程比較多。
2.2、創建與調用存儲過程
創建存儲過程語法:下面舉出一些簡單的例子
(1)無參數的形式
前面我就利用了存儲過程批量插入數據,在回顧下,只是我們沒有利用參數傳遞,那就很不靈活了,如果下次插入1000條呢?
#下面這就是創建存儲過程,實現批量插入數據,這個後面我會寫博客介紹的,在這裏就是實現批量插入數據的功能
create procedure autoinsert()
begin
declare i int default 1;
while(i<200000)do
insert into company.t1 values(i,'ggg');
set i=i+1;
end while;
end$$
delimiter ; #把分隔符修改回來
call autoinsert(); #執行這個函數,開始插入數據
(2)參數形式:IN,利用它可以傳入參數方便之後修改,變得靈活!重新看一個例子。md5()是個函數,計算哈希值的。
delimiter $$
create procedure autoinsert3(IN a int)
-> begin
-> declare i int default 1;
-> while(i<=a)do
-> insert into student.autoinsert values(i,md5(i));
-> set i=i+1;
-> end while;
-> end$$
delimiter ;
call autoinsert3(10);
select * from autoinsert;
+------+----------------------------------+
| id | name |
+------+----------------------------------+
| 1 | c4ca4238a0b923820dcc509a6f75849b |
| 2 | c81e728d9d4c2f636f067f89cc14862c |
| 3 | eccbc87e4b5ce2fe28308fd9f2a7baf3 |
| 4 | a87ff679a2f3e71d9181a67b7542122c |
| 5 | e4da3b7fbbce2345d7772b0674a318d5 |
| 6 | 1679091c5a880faf6fb5e6087eb1b2dc |
| 7 | 8f14e45fceea167a5a36dedd4bea2543 |
| 8 | c9f0f895fb98ab9159f51fd0297e236d |
| 9 | 45c48cce2e2d7fbdea1afc51c7c6ad26 |
| 10 | d3d9446802a44259755d38e6d163e820 |
+------+----------------------------------+
(3)out 用法參例:
delimiter $$
create procedure p2 (out param1 int) --創建存儲過程
-> begin
-> select count(*) into param1 from mysql.user;
-> end$$
delimiter ;
select @a; --查看a變量是否爲空,爲空後面讓它傳參
call p2(@a); --調用參數
select @a; --可以直接用變量查詢和後面的select語句是一樣的
+------+
| @a |
+------+
| 4 |
+------+
select count(*) from mysql.user;
+----------+
| count(*) |
+----------+
| 4 |
+----------+
(4)in和out同時用,參例如下:
#統計指定部門的員工數
mysql> delimiter $$
mysql> create procedure count_num(in p1 varchar(50),out p2 int)
-> begin
-> select count(*) into p2 from company.employee
-> where post=p1;
-> end$$
mysql> delimiter ;
mysql> call count_num('sale',@b);
mysql> select @b;
+------+
| @b |
+------+
| 4 |
+------+
#統計指定部門工資超過例如2000的總人數
mysql> delimiter $$
mysql> create procedure count_num1(in p1 varchar(50),in p2 float(10,2),out p3 int)
-> begin
-> select count(*) into p3 from company.employee
-> where post=p1 and salary>=p2;
-> end$$
mysql> call count_num1('hr',2000,@c)$$
mysql> select @C$$
+------+
| @C |
+------+
| 1 |
+------+
(5)inout參例
create procedure inout_test(inout p1 int) begin if(p1 is not null)then set p1=p1+1; else set p1=100; end if; end$$
call inout_test(@e)$$
select(@e)$$
+------+
| (@e) |
+------+
| 100 |
+------+
call inout_test(@e)$$
select(@e)$$
+------+
| (@e) |
+------+
| 101 |
+------+
2.3 創建函數
在我創建函數的時候出現以下錯誤,百度了下修改下就可以了
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
set global log_bin_trust_function_creators=TRUE;
參例:
create function name_from_emp(a int) returns varchar(50) begin return(select name from employee where id=a); end$$
select name_from_emp(5)$$
+------------------+
| name_from_emp(5) |
+------------------+
| jack |
+------------------+
select * from employee where name=name_from_emp(5)$$ --查看全部信息也可調用這個函數
+----+------+------+------------+------------+-----------------+---------+--------+--------+
| id | name | sex | hire_date | post | job_description | salary | office | dep_id |
+----+------+------+------------+------------+-----------------+---------+--------+--------+
| 5 | jack | male | 2018-02-02 | instructor | teach | 5000.00 | 501 | 100 |
+----+------+------+------------+------------+-----------------+---------+--------+--------
2.4 存儲過程和函數的維護
這個和之前的table,index等差不多,如下:
在創建存儲過程的時候,多了變量這個概念,mysql變量的術語一般用得着是用戶變量和全局變量:
1.用戶變量:以"@"開始,形式爲"@變量名",由客戶端定義的變量。
用戶變量跟mysq|客戶端是綁定的, 設置的變量只對當前用戶使用的客戶端生效,當用戶斷開連接自動釋放。
2.全局變量:定義時如下兩種形式, set GLOBAL變量名或者set @@global.變量名
對所有客戶端生效,但只有具有super管理員的權限纔可以設置全局變量。
這個做個瞭解,後面還會用的着的。