MySQL學習(十六)
MySQL高階部分
觸發器
觸發器是一類特殊的事務,可以監視某種資料操作(insert/update/delete),並觸發相關的操作(insert/update/delete)
觸發器建立語法之4要素
1 監視地點table
2 監視事件insert/update/delete
3 觸發時間after/before
4 觸發事件
檢視已有的觸發器
show triggers
刪除已有的觸發器
drop trigger triggerName
建立一個觸發器
create trigger t1 after insert on ord for each row begin update goods1 set num = num - 2 where gid = 1; end$
上面語句中,如果insert(被監視的語句),產生的資料,能否在觸發器中引用到?
更改之後的觸發器,引入了引數
create trigger t2
after
insert on ord
for each row
begin
update goods1 set num = num -new.much where gid = new.gid;
end$
刪除訂單的觸發器
create trigger t3 after delete on ord for each row begin update goods1 set num = num + old.much where gid = old.gid; end$
改訂單數量
create trigger t4
before
update
on ord
for each row
begin
update goods1 set num = num + (old.much - new.much) where gid = old.gid;
end$
思考:before目前似乎沒有看出與after的區別?
再思考:如果剩餘的庫存量只有3個,但客戶要買10個,就會出現問題
一個問題
能否在購買量 much > 庫存量num時,把much自動改為num
提示:before的作用
在t2的基礎上,完成much與num的判斷
create trigger t5 after insert on ord for each row begin declare rnum int; select num into rnum from goods1 where gid = new.gid; if new.much > rnum then set new.much = rnum; end if update goods1 set num = num -new.much where gid = new.gid; end$
提示錯誤
ERROR 1362 (HY000): Updating of NEW row is not allowed in after trigger
原因:insert之後,new行已經插入到表中,成為事實,改new已經晚了
修改
在t2的基礎上,完成much與num的判斷
create trigger t5
before
insert on ord
for each row
begin
declare
rnum int;
select num into rnum from goods1 where gid = new.gid;
if new.much > rnum then
set new.much = rnum;
end if;
update goods1 set num = num -new.much where gid = new.gid;
end$
insert 只能引用新行 new
delete 只能引用舊行 old
update可以引用新行和舊行,新行為new,舊行為old
觸發器for each row是幹嗎的?
在oracle的觸發器中,觸發器可以分為語句級觸發器和行級觸發器
執行
update xxtable set xxx=xxx where id > 100; #修改了100行
那麼sqlN會被觸發幾次?
100次
create trigger t5
before
insert on ord
for each row #每一行受影響,觸發器都執行,叫做行級觸發器
begin
declare
rnum int;
select num into rnum from goods1 where gid = new.gid;
if new.much > rnum then
set new.much = rnum;
end if;
update goods1 set num = num -new.much where gid = new.gid;
end$
在orcal中
for each row如果不寫,無論update語句一次影響了多少行,都只執行一次。
比如:1人下了訂單,買了5件商品,insert 5 次,可以用行級觸發器,修改5次庫存,
用語句級觸發,insert一條發貨提醒。
遺憾的是,MySQL目前不支援語句級觸發器。
for each row 宣告行級觸發器
儲存過程和函式
建立儲存過程的語法
create procedure procedureName()
begin
--sql語句
end$
呼叫儲存過程
call procedure();
刪除儲存過程
drop procedure procedureName
建立儲存過程語法
create procedure p1()
begin
select 'hello' from dual;
end$
儲存過程是可以程式設計的,意味著可以使用變數,表示式,控制結構來完成複雜的功能
在儲存過程中,用declare宣告變數
格式 declare 變數名 變數型別 [default 預設值]
引入變數
create procedure p2()
begin
declare age int default 18;
declare height int default 180;
select concat('年齡是',age,'身高是',height);
end$
儲存過程中,變數可以做sql語句中合法的運算,如加減乘除,
注意,運算的結果,如何賦值給變數
set 變數名 := expression
create procedure p3()
begin
declare age int default 18;
declare height int default 180;
set age := age + 20;
select concat('年齡是',age,'身高是',height);
end$
if/else控制結構
if condition then
statement
else
end;
儲存過程的括號裡可以宣告引數
語法是 [in/out/inout] 引數名 引數型別
給儲存過程傳遞引數
create procedure p6(width int,height int)
begin
declare area int default 0;
if width > height then
select '這個矩形比較寬';
elseif width < height then
select '這個矩形比較高';
else
select '這個矩形是個方的';
end if;
set area := width * height;
select area;
end$
控制結構有三大類,順序,選擇,迴圈。
while的語法
WHILE expr_condition DO
statement_list
END WHILE
create procedure p7()
begin
declare total int default 0;
declare num int default 0;
while num < 101 do
set total := total + num;
set num := num + 1;
end while;
select total;
end$
in型別的引數,in代表input
create procedure p8(in n int)
begin
declare total int default 0;
declare num int default 0;
while num < n do
set num := num + 1;
set total := total + num;
end while;
select total;
end$
out型
create procedure p9(in n int,out total int)
begin
declare num int default 0;
set total := 0;
while num < n do
set num := num + 1;
set total := total + num;
end while;
end$
呼叫
call p9(100,@sum)$
select @sum$
inout型別
CASE,LOOP,IF,LEAVE,ITERATE,REPEAT,WHILE語句