06-Re: 檢視&過程&觸發器
檢視
檢視概述
檢視(View)是一種虛擬存在的表。檢視並不在資料庫中實際存在,行和列資料來自定義檢視的查詢中使用的表,並且是在使用檢視時動態生成的。通俗的講,檢視就是一條 SELECT 語句執行後返回的結果集。所以我們在建立檢視的時候,主要的工作就落在建立這條 SQL 查詢語句上。
檢視相對於普通的表的優勢主要包括以下幾項:
- 簡單:使用檢視的使用者完全不需要關心後面對應的表的結構、關聯條件和篩選條件,對使用者來說已經是過濾好的複合條件的結果集。
- 安全:使用檢視的使用者只能訪問他們被允許查詢的結果集,對錶的許可權管理並不能限制到某個行某個列,但是通過檢視就可以簡單的實現。
- 資料獨立:一旦檢視的結構確定了,可以遮蔽表結構變化對使用者的影響,源表增加列對檢視沒有影響;源表修改列名,則可以通過修改檢視來解決,不會造成對訪問者的影響。
建立或修改檢視
建立檢視的語法為:
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
修改檢視的語法為:
ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION]
選項:
WITH [CASCADED | LOCAL] CHECK OPTION 決定了是否允許更新資料使記錄不再滿足檢視的條件。
LOCAL:只要滿足本檢視的條件就可以更新。
CASCADED(預設值):必須滿足所有針對該檢視的所有檢視的條件才可以更新。
檢視檢視
從 MySQL 5.1 版本開始,使用 SHOW TABLES
命令的時候不僅顯示錶的名字,同時也會顯示檢視的名字,而不存在單獨顯示檢視的 SHOW VIEWS
命令。
同樣,在使用 SHOW TABLE STATUS\G
命令的時候,不但可以顯示錶的資訊,同時也可以顯示檢視的資訊。
如果需要查詢某個檢視的定義,可以使用 SHOW CREATE VIEW\G
刪除檢視
語法
DROP VIEW [IF EXISTS] view_name [, view_name] ...[RESTRICT | CASCADE]
示例:刪除檢視 city_country_view
DROP VIEW city_country_view;
儲存過程和函式
概述
儲存過程和函式是事先經過編譯並存儲在資料庫中的一段 SQL 語句的集合,呼叫儲存過程和函式可以簡化應用開發人員的很多工作,減少資料在資料庫和應用伺服器之間的傳輸,對於提高資料處理的效率是有好處的。儲存過程和函式的區別在於函式必須有返回值,而儲存過程沒有。
- 函式:是一個有返回值的過程。
- 過程:是一個沒有返回值的函式。
基本操作
建立儲存過程
語法:
CREATE PROCEDURE procedure_name ([proc_parameter[,...]])
BEGIN
-- SQL語句
END;
示例:
DELIMITER $
CREATE PROCEDURE pro_test1()
BEGIN
select 'Hello Mysql';
END$
DELIMITER ;
呼叫儲存過程
CALL procedure_name();
檢視儲存過程
-- 查詢db_name資料庫中的所有的儲存過程
select name from mysql.proc where db='db_name';
-- 查詢儲存過程的狀態資訊
show procedure status;
-- 查詢某個儲存過程的定義
show create procedure mydb.pro_test1\G;
刪除儲存過程
DROP PROCEDURE [IF EXISTS] sp_name;
語法
儲存過程是可以程式設計的,意味著可以使用變數、表示式、控制結構,來完成比較複雜的功能。
變數
- DECLARE
- 通過
DECLARE
可以定義一個區域性變數,該變數的作用範圍只能在BEGIN...END
塊中。具體語法如下:DECLARE var_name[,...] type [DEFAULT value]
- 示例
DELIMITER $ CREATE PROCEDURE pro_test2() BEGIN DECLARE num int default 5; SELECT num + 10; END$ DELIMITER ;
- 通過
- SET
- 直接賦值使用
SET
,可以賦常量或者賦表示式,具體語法如下:SET var_name = expr [, var_name = expr] ...
- 示例
DELIMITER $ CREATE PROCEDURE pro_test3() BEGIN DECLARE name varchar(20); SET name = 'MYSQL'; SELECT name; END$ DELIMITER ;
- 直接賦值使用
- SELECT INTO
DELIMITER $ CREATE PROCEDURE pro_test5() BEGIN DECLARE countnum int; SELECT count(*) INTO countnum FROM city; # 進行賦值操作 SELECT countnum; END$ DELIMITER ;
if 條件判斷
語法結構
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF;
示例:根據定義的身高變數,判定當前身高的所屬的身材型別
DELIMITER $
create procedure pro_test6()
BEGIN
declare height int default 175;
declare description varchar(50);
if height >= 180 then
set description = '身材高挑';
elseif height >= 170 and height < 180 then
set description = '標準身材';
else
set description = '一般身材';
end if;
select description;
END$
DELIMITER ;
傳遞引數
語法格式
create procedure procedure_name([in/out/inout] 引數名 引數型別)
...
IN 預設,該引數可以作為輸入,也就是需要呼叫方傳入值
OUT 該引數作為輸出,也就是該引數可以作為返回值
INOUT 既可以作為輸入引數,也可以作為輸出引數
IN-輸入
# 根據入參的身高,判定當前身高的所屬的身材型別
DELIMITER $
create procedure pro_test5(in height int)
begin
declare description varchar(50) default '';
if height >= 180 then
set description='身材高挑';
elseif height >= 170 and height < 180 then
set description='標準身材';
else
set description='一般身材';
end if;
select concat('身高 ', height , '對應的身材型別為:',description);
end$
DELIMITER ;
OUT-輸出
# 根據傳入的身高變數,獲取當前身高的所屬的身材型別
DELIMITER $
create procedure pro_test5(in height int , out description varchar(100))
begin
if height >= 180 then
set description='身材高挑';
elseif height >= 170 and height < 180 then
set description='標準身材';
else
set description='一般身材';
end if;
end$
DELIMITER ;
CALL pro_test5(168, @description);
select @description;
補充:
- @description : 這種變數要在變數名稱前面加上 '@' 符號,叫做使用者會話變數,代表整個會話過程它都是有作用的,這個類似於全域性變數一樣。
- @@global.sort_buffer_size:這種在變數前加上 '@@' 符號, 叫做系統變數。
case 結構
語法結構
方式一:
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE;
方式二:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE;
示例:給定一個月份, 然後計算出所在的季度
DELIMITER $
create procedure pro_test9(month int)
begin
declare result varchar(20);
case
when month >= 1 and month <=3 then
set result = '第一季度';
when month >= 4 and month <=6 then
set result = '第二季度';
when month >= 7 and month <=9 then
set result = '第三季度';
when month >= 10 and month <=12 then
set result = '第四季度';
end case;
select concat('您輸入的月份為:', month , ' , 該月份為: ' , result) as content ;
end$
DELIMITER ;
while 迴圈
語法結構
WHILE search_condition DO
statement_list
END WHILE;
示例:計算從 1 加到 n 的值
DELIMITER $
create procedure pro_test8(n int)
begin
declare total int default 0;
declare num int default 1;
while num<=n do
set total = total + num;
set num = num + 1;
end while;
select total;
end$
DELIMITER ;
repeat 結構
有條件的迴圈控制語句, 當滿足條件的時候退出迴圈 。while 是滿足條件才執行,repeat 是滿足條件就退出迴圈。具體語法如下:
REPEAT
statement_list
UNTIL search_condition # 注意!這裡沒有分號
END REPEAT;
示例:計算從 1 加到 n 的值
DELIMITER $
create procedure pro_test10(n int)
begin
declare total int default 0;
repeat
set total = total + n;
set n = n - 1;
until n=0
end repeat;
select total ;
end$
DELIMITER ;
loop & leave
LOOP 實現簡單的迴圈,退出迴圈的條件需要使用其他的語句定義,通常可以使用 LEAVE 語句實現,具體語法如下:
[begin_label:] LOOP
statement_list
END LOOP [end_label]
如果不在 statement_list 中增加退出迴圈的語句,那麼 LOOP 語句可以用來實現簡單的死迴圈。
用來從標註的流程構造中退出,通常和 BEGIN ... END
或者迴圈一起使用。下面是一個使用 LOOP 和 LEAVE 的簡單例子,退出迴圈:
DELIMITER $
CREATE PROCEDURE pro_test11(n int)
BEGIN
DECLARE total int DEFAULT 0;
ins: LOOP
IF n <= 0 then
leave ins;
END IF;
SET total = total + n;
SET n = n - 1;
END LOOP ins;
SELECT total;
END$
DELIMITER ;
遊標/游標
遊標是用來儲存查詢結果集的資料型別,在儲存過程和函式中可以使用游標對結果集進行迴圈的處理。游標的使用包括游標的宣告、OPEN、FETCH 和 CLOSE,其語法分別如下。
- 宣告游標:
DECLARE cursor_name CURSOR FOR select_statement;
- OPEN 游標:
OPEN cursor_name;
- FETCH 游標:
FETCH cursor_name INTO var_name [, var_name] ...;
- CLOSE 游標:
CLOSE cursor_name;
示例:遍歷 emp 表中的記錄。
初始化指令碼
create table emp(
id int(11) not null auto_increment ,
name varchar(50) not null comment '姓名',
age int(11) comment '年齡',
salary int(11) comment '薪水',
primary key(`id`)
)engine=innodb default charset=utf8;
insert into emp(id,name,age,salary) values
(null,'金毛獅王',55,3800),
(null,'白眉鷹王',60,4000),
(null,'青翼蝠王',38,2800),
(null,'紫衫龍王',42,1800);
通過迴圈結構,獲取遊標中的資料:
DELIMITER $
CREATE PROCEDURE pro_test11()
BEGIN
DECLARE e_id int(11);
DECLARE e_name varchar(50);
DECLARE e_age int(11);
DECLARE e_salary int(11);
DECLARE has_data int DEFAULT 1;
DECLARE emp_result CURSOR FOR select * from emp;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET has_data=0;
OPEN emp_result;
REPEAT
FETCH emp_result INTO e_id, e_name, e_age, e_salary;
SELECT CONCAT('id=',e_id , ', name=',e_name, ', age=', e_age, ', 薪資為:',e_salary);
UNTIL has_data = 0
END REPEAT;
CLOSE emp_result;
END$
DELIMITER ;
函式
語法結構
CREATE FUNCTION function_name([param type ... ])
RETURNS type
BEGIN
...
END;
示例:定義一個儲存過程,請求滿足條件的總記錄數。
DELIMITER $
create function count_city(countryId int)
returns int
BEGIN
DECLARE cnum int;
select count(*) into cnum from city where country_id = countryId;
RETURN cnum;
END$
DELIMITER ;
呼叫
select count_city(1);
select count_city(2);
觸發器
簡述
觸發器是與表有關的資料庫物件,指在 insert/update/delete 之前或之後,觸發並執行觸發器中定義的 SQL 語句集合。觸發器的這種特性可以協助應用在資料庫端確保資料的完整性、日誌記錄、資料校驗等操作 。
使用別名 OLD 和 NEW (也稱為“行記錄變數”)來引用觸發器中發生變化的記錄內容,這與其他的資料庫是相似的。現在觸發器還只支援行級觸發,不支援語句級觸發。
建立觸發器
語法結構
CREATE TRIGGER trigger_name
BEFORE/AFTER insert/update/delete
ON tbl_name
[ FOR EACH ROW ] -- 行級觸發器
BEGIN
trigger_stmt;
END;
示例:通過觸發器記錄 emp 表的資料變更日誌,包含增加、修改、刪除。
- 首先建立一張日誌表
create table emp_logs( id int(11) not null auto_increment, operation varchar(20) not null comment '操作型別, insert/update/delete', operate_time datetime not null comment '操作時間', operate_id int(11) not null comment '操作表的ID', operate_params varchar(500) comment '操作引數', primary key(`id`) )engine=innodb default charset=utf8;
- 建立 insert 型觸發器,完成插入資料時的日誌記錄。
DELIMITER $ CREATE TRIGGER emp_logs_insert_trigger AFTER insert ON emp for each row BEGIN insert into emp_logs (id,operation,operate_time,operate_id,operate_params) values (null, 'insert', now(), new.id, concat('插入後(id:', new.id, ',name:', new.name, ',age:', new.age, ',salary:', new.salary, ')')); END $ DELIMITER ;
- 建立 update 型觸發器,完成更新資料時的日誌記錄。
DELIMITER $ CREATE TRIGGER emp_logs_update_trigger AFTER update ON emp for each row BEGIN insert into emp_logs (id,operation,operate_time,operate_id,operate_params) values(null, 'update', now(), new.id, concat('修改前(id:', old.id, ',name:', old.name, ',age:', old.age, ',salary:', old.salary, '),修改後(id', new.id, 'name:', new.name, ',age:', new.age, ',salary:', new.salary, ')')); END $ DELIMITER ;
- 建立 delete 行的觸發器,完成刪除資料時的日誌記錄。
DELIMITER $ CREATE TRIGGER emp_logs_delete_trigger AFTER delete ON emp for each row BEGIN insert into emp_logs (id,operation,operate_time,operate_id,operate_params) values(null, 'delete', now(), old.id, concat('刪除前(id:', old.id, ',name:', old.name, ',age:', old.age, ',salary:', old.salary, ')')); END $ DELIMITER ;
刪除觸發器
DROP TRIGGER [schema_name.]trigger_name
如果沒有指定 schema_name,預設為當前資料庫 。
檢視觸發器
可以通過執行 SHOW TRIGGERS 命令檢視觸發器的狀態、語法等資訊。
SHOW TRIGGERS\G;