SQL及其使用(1)
3.1、觸發器
3.1.1、觸發器的作用
- 安全性。可以基於數據庫的值使用戶具有操作數據庫的某種權利。
可以基於時間限制用戶的操作,例如不允許下班後和節假日修改數據庫數據。
可以基於數據庫中的數據限制用戶的操作,例如不允許股票的價格的升幅一次超過10%。
- 審計。可以跟蹤用戶對數據庫的操作。
審計用戶操作數據庫的語句。
把用戶對數據庫的更新寫入審計表。
- 實現複雜的數據完整性規則
實現非標準的數據完整性檢查和約束。觸發器可產生比規則更爲複雜的限制。與規則不同,觸發器可以引用列或數據庫對象。例如,觸發器可回退任何企圖吃進超過自己
保證金的期貨。
- 提供可變的缺省值。
- 實現複雜的非標準的數據庫相關完整性規則。觸發器可以對數據庫中相關的表進行連環更新。例如,在auths表author_code列上的刪除觸發器可導致相應刪除在其它表中的與之匹配的行。
在修改或刪除時級聯修改或刪除其它表中的與之匹配的行。
在修改或刪除時把其它表中的與之匹配的行設成NULL值。
在修改或刪除時把其它表中的與之匹配的行級聯設成缺省值。
觸發器能夠拒絕或回退那些破壞相關完整性的變化,取消試圖進行數據更新的事務。當插入一個與其主健不匹配的外部鍵時,這種觸發器會起作用。例如,可以在
books.author_code 列上生成一個插入觸發器,如果新值與auths.author_code列中的某值不匹配時,插入被回退。
- 同步實時地複製表中的數據。
- 自動計算數據值,如果數據的值達到了一定的要求,則進行特定的處理。例如,如果公司的帳號上的資金低於5萬元則立即給財務人員發送警告數據。
3.1.2、觸發器的基本語法
1、觸發器的創建
CREATETRIGGER <觸發器名稱> --觸發器必須有名字,最多64個字符,可能後面會附有分隔符.它和MySQL中其他對象的命名方式基本相象.
{BEFORE | AFTER } --觸發器有執行的時間設置:可以設置爲事件發生前或後。
{INSERT | UPDATE | DELETE } --同樣也能設定觸發的事件:它們可以在執行insert、update或delete的過程中觸發。
ON <表名稱> --觸發器是屬於某一個表的:當在這個表上執行插入、 更新或刪除操作的時候就導致觸發器的激活. 我們不能給同一張表的同一個事件安排兩個觸發器。
FOR EACH ROW --觸發器的執行間隔:FOR EACH ROW子句通知觸發器 每隔一行執行一次動作,而不是對整個表執行一次。
<觸發器SQL語句> --觸發器包含所要觸發的SQL語句:這裏的語句可以是任何合法的語句, 包括複合語句,但是這裏的語句受的限制和函數的一樣。
create trigger trigger_name
{after | before} { insert | update | delete } on table_namefor each row
begin
SQL語句/SQL變量
end;
2、觸發器的刪除:
drop trigger if exists trigger_name
3、觸發器之new old 方法
"NEW . column_name"或者"OLD . column_name".這樣在技術上處理(NEW | OLD . column_name)新和舊的列名屬於創建了過渡變量("transition variables")。
對於INSERT語句,只有NEW是合法的;對於DELETE語句,只有OLD才合法;而UPDATE語句可以在和NEW以及OLD同時使用。
3.1.3、示例
1、使用示例
測試數據庫:
create table shares(idvarchar(10),price int);
create table sharescopy(id varchar(10),price int);
示例1:同步實時複製數據表
create trigger after_insert_shares afterinsert on shares for each row
begin
insert into sharescopy values(new.id,new.price);
end;
示例2:不允許股票的價格的升幅一次超過10%
create trigger before_update_shares before updateon shares for each row
begin
ifnew.price >old.price*1.1 then
setnew.price = old.price*1.1;
endif;
end;
示例3:不允許下班後和節假日修改數據庫數據
create trigger change_shares before updateon shares for each row
begin
if (now() >str_to_date('2017-5-29 14:20:00','%Y-%m-%d %T')) then
insert into xxx values(1);
end if;
end;
MySQL 不像其它有些數據庫可以在觸發器中拋出異常來中斷當然觸發器的執行以阻止相應的SQL語句的執行。在MySQL的目錄版本中還無法直接拋出異常。可通過執行錯誤的SQL來中斷執行。
2、MySql觸發器的問題
mysql 觸發器的問題Can't update table 'tbl' in storedfunction/trigger because it is already used by state。如果你在觸發器裏面對剛剛插入的數據進行了 insert/update,則出現這個問題。因爲會造成循環的調用.
如下面的語句會出現上述的錯誤:
create trigger before_update_shares beforeupdate on shares for each row
begin
ifnew.price >old.price*1.1 then
updateshares set new.price = old.price*1.1 where id =new.id;
endif;
end;
正確的用法是示例2
3、MySql中 delimiter
delimiter的作用告訴MySQL解釋器,該段命令是否已經結束了,mysql是否可以執行了。默認情況下,delimiter默認是分號;。在命令行客戶端中,如果有一行命令以分號結束,那麼回車後,mysql將會執行該命令。但有時候,不希望MySQL這麼做。因爲可能輸入較多的語句,且語句中包含有分號(如上面觸發器的創建),這種情況下,就需要事先把delimiter換成其它符號,一般是//或$$。
如果直接用上述的命令創建觸發器,由於delimiter默認是分號,上述語句會出現語法錯誤,可做如下修改。
delimiter //
create trigger after_insert_shares after insert on shares for each row
begin
insert into sharescopy values(new.id,new.price);
end;//
delimiter ; // 將delimiter改爲默認的分號;