国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

MySQL函數(shù)、視圖、存儲過程及觸發(fā)器

這篇具有很好參考價值的文章主要介紹了MySQL函數(shù)、視圖、存儲過程及觸發(fā)器。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

MySQL在我們工作中都會用到,那么我們最常接觸的就是增刪改查,而對于增刪改查來說,我們更多的是查詢。但是面試中,面試官又不會問你什么查詢是怎么寫的,都是問一些索引啊,事務啊, 底層結(jié)構(gòu)這些東西,所以我打算分四篇去逐一的過一遍MySQL的知識點。
以下為四篇的傳送門,有需要直接點擊進入,目前還在建設當中,可以關(guān)注作者或?qū)冢掷m(xù)更新,永不收費。
MySQL函數(shù)、視圖、存儲過程及觸發(fā)器

篇章 地址
DDL查詢篇 傳送門
MySQL函數(shù)、視圖、存儲過程及觸發(fā)器 傳送門
MySQL約束、索引及優(yōu)化
MySQL事務及架構(gòu)

一、函數(shù)

MySQL函數(shù)、視圖、存儲過程及觸發(fā)器

1.單行函數(shù)

因為函數(shù)很多,全部例舉讀者也找不到重點,而且工作中也用不到,沒有必要。所以在此僅列出本人認為比較重要和常用的。您可以在評論區(qū)補充~

1.1 數(shù)值函數(shù)

函數(shù) 用法
ABS(x) 返回x的絕對值
CEIL(x),CEILING(x) 返回大于或等于某個值的最小整數(shù)
FLOOR(x) 返回小于或等于某個值的最大整數(shù)
LEAST(e1,e2,e3…) 返回列表中的最小值
GREATEST(e1,e2,e3…) 返回列表中的最大值
MOD(x,y) 返回X除以Y后的余數(shù)
RAND() 返回0~1的隨機值
RAND(x) 返回0~1的隨機值,其中x的值用作種子值,相同的X值會產(chǎn)生相同的隨機 數(shù)
ROUND(x) 返回一個對x的值進行四舍五入后,最接近于X的整數(shù)
ROUND(x,y) 返回一個對x的值進行四舍五入后最接近X的值,并保留到小數(shù)點后面Y位
TRUNCATE(x,y) 返回數(shù)字x截斷為y位小數(shù)的結(jié)果

1.2 字符串函數(shù)

函數(shù) 用法
CONCAT(s1,s2,…,sn) 連接s1,s2,…,sn為一個字符串
CONCAT_WS(x, s1,s2,…,sn) 同CONCAT(s1,s2,…)函數(shù),但是每個字符串之間要加上x
REPLACE(str, a, b) 用字符串b替換字符串str中所有出現(xiàn)的字符串a(chǎn)
UPPER(s) 或 UCASE(s) 將字符串s的所有字母轉(zhuǎn)成大寫字母
LOWER(s) 或LCASE(s) 將字符串s的所有字母轉(zhuǎn)成小寫字母
LEFT(str,n) 返回字符串str最左邊的n個字符
RIGHT(str,n) 返回字符串str最右邊的n個字符
LPAD(str, len, pad) 用字符串pad對str最左邊進行填充,直到str的長度為len個字符
RPAD(str ,len, pad) 用字符串pad對str最右邊進行填充,直到str的長度為len個字符
LTRIM(s) 去掉字符串s左側(cè)的空格
RTRIM(s) 去掉字符串s右側(cè)的空格
TRIM(s) 去掉字符串s開始與結(jié)尾的空格
TRIM(s1 FROM s) 去掉字符串s開始與結(jié)尾的s1
TRIM(LEADING s1 FROM s) 去掉字符串s開始處的s1
TRIM(TRAILING s1 FROM s) 去掉字符串s結(jié)尾處的s1
SUBSTR(s,index,len) 返回從字符串s的index位置其len個字符,作用與SUBSTRING(s,n,len)、 MID(s,n,len)相同
FIND_IN_SET(s1,s2) 返回字符串s1在字符串s2中出現(xiàn)的位置。其中,字符串s2是一個以逗號分隔的字符串
REVERSE(s) 返回s反轉(zhuǎn)后的字符串
NULLIF(value1,value2) 比較兩個字符串,如果value1與value2相等,則返回NULL,否則返回 value1

注意:MySQL中,字符串的位置是從1開始的。

1.3 日期和時間函數(shù)

函數(shù) 用法
CURDATE() ,CURRENT_DATE() 返回當前日期,只包含年、 月、日
CURTIME() , CURRENT_TIME() 返回當前時間,只包含時、 分、秒
NOW() / SYSDATE() / CURRENT_TIMESTAMP() / LOCALTIME() / LOCALTIMESTAMP() 返回當前系統(tǒng)日期和時間
YEAR(date) / MONTH(date) / DAY(date) 返回具體的日期值
HOUR(time) / MINUTE(time) / SECOND(time) 返回具體的時間值
WEEK(date) , WEEKOFYEAR(date) 返回一年中的第幾周
DAYOFYEAR(date) 返回日期是一年中的第幾天
DAYOFMONTH(date) 返回日期位于所在月份的第幾天
ADDTIME(time1,time2) 返回time1加上time2的時間。當time2為一個數(shù)字時,代表的是 秒 ,可以為負數(shù)
SUBTIME(time1,time2) 返回time1減去time2后的時間。當time2為一個數(shù)字時,代表的 是 秒 ,可以為負數(shù)
DATEDIFF(date1,date2) 返回date1 - date2的日期間隔天數(shù)
TIMEDIFF(time1, time2) 返回time1 - time2的時間間隔
LAST_DAY(date) 返回date所在月份的最后一天的日期
PERIOD_ADD(time,n) 返回time加上n后的時間

格式符

格式符 說明 格式符 說明
%Y 4位數(shù)字表示年份 %y 表示兩位數(shù)字表示年份
%M 月名表示月份(January,…) %m 兩位數(shù)字表示月份 (01,02,03。。。)
%b 縮寫的月名(Jan.,F(xiàn)eb.,…) %c 數(shù)字表示月份(1,2,3,…)
%D 英文后綴表示月中的天數(shù) (1st,2nd,3rd,…) %d 兩位數(shù)字表示月中的天數(shù)(01,02…)
%e 數(shù)字形式表示月中的天數(shù) (1,2,3,4,5…)
%H 兩位數(shù)字表示小數(shù),24小時制 (01,02…) %h 和%I 兩位數(shù)字表示小時,12小時制 (01,02…)
%k 數(shù)字形式的小時,24小時制(1,2,3) %l 數(shù)字形式表示小時,12小時制 (1,2,3,4…)
%i 兩位數(shù)字表示分鐘(00,01,02) %S 和%s 兩位數(shù)字表示秒(00,01,02…)
%W 一周中的星期名稱(Sunday…) %a 一周中的星期縮寫(Sun., Mon.,Tues.,…)
%w 以數(shù)字表示周中的天數(shù) (0=Sunday,1=Monday…)
%j 以3位數(shù)字表示年中的天數(shù)(001,002…) %U 以數(shù)字表示年中的第幾周, (1,2,3。。)其中Sunday為周中第一 天
%u 以數(shù)字表示年中的第幾周, (1,2,3。。)其中Monday為周中第一 天
%T 24小時制 %r 12小時制
%p AM或PM %% 表示%

1.4 流程控制函數(shù)

函數(shù) 用法
IF(value,value1,value2) 如果value的值為TRUE,返回value1, 否則返回value2
IFNULL(value1, value2) 如果value1不為NULL,返回value1,否則返回value2
CASE WHEN 條件1 THEN 結(jié)果1 WHEN 條件2 THEN 結(jié)果2 … [ELSE resultn] END 相當于Java的if…else if…else…
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 … [ELSE 值n] END 相當于Java的switch…case…

1.5 加密與解密函數(shù)

函數(shù) 用法
PASSWORD(str) 返回字符串str的加密版本,41位長的字符串。加密結(jié)果不可逆 ,常用于用戶的密碼加密
MD5(str) 返回字符串str的md5加密后的值,也是一種加密方式。若參數(shù)為 NULL,則會返回NULL
SHA(str) 從原明文密碼str計算并返回加密后的密碼字符串,當參數(shù)為 NULL時,返回NULL。 SHA加密算法比MD5更加安全 。
ENCODE(value,password_seed) 返回使用password_seed作為加密密碼加密value
DECODE(value,password_seed) 返回使用password_seed作為加密密碼解密value

2.聚合函數(shù)

  • 什么是聚合函數(shù)

聚合函數(shù)作用于一組數(shù)據(jù),并對一組數(shù)據(jù)返回一個值。

  • 聚合函數(shù)類型
    • AVG()
    • SUM()
    • MAX()
    • MIN()
    • COUNT()

2.1 AVG和SUM函數(shù)

SELECT AVG(salary), MAX(salary),MIN(salary), SUM(salary)
FROM employees
WHERE job_id LIKE '%REP%';

2.2MIN和MAX函數(shù)

可以對任意數(shù)據(jù)類型的數(shù)據(jù)使用 MIN 和 MAX 函數(shù)。

SELECT MIN(hire_date), MAX(hire_date)
FROM employees;

2.3COUNT函數(shù)

COUNT(*)返回表中記錄總數(shù),適用于任意數(shù)據(jù)類型。

SELECT COUNT(*)
FROM employees
WHERE department_id = 50;

COUNT(expr) 返回expr不為空的記錄總數(shù)。

SELECT COUNT(commission_pct)
FROM employees
WHERE department_id = 50;
  • 問題:用count(*),count(1),count(列名)誰好呢?

其實,對于MyISAM引擎的表是沒有區(qū)別的。這種引擎內(nèi)部有一計數(shù)器在維護著行數(shù)。 Innodb引擎的表用count(*),count(1)直接讀行數(shù),復雜度是O(n),因為innodb真的要去數(shù)一遍。但好 于具體的count(列名)。

  • 問題:能不能使用count(列名)替換count(*)?

不要使用 count(列名)來替代 count() , count() 是 SQL92 定義的標準統(tǒng)計行數(shù)的語法,跟數(shù) 據(jù)庫無關(guān),跟 NULL 和非 NULL 無關(guān)。 說明:count(*)會統(tǒng)計值為 NULL 的行,而 count(列名)不會統(tǒng)計此列為 NULL 值的行。

2.4 GROUP BY

2.4.1 基本使用

可以使用GROUP BY子句將表中的數(shù)據(jù)分成若干組

SELECT column, group_function(column)
FROM table
[WHERE condition]
[GROUP BY group_by_expression]
[ORDER BY column];

結(jié)論1:SELECT中出現(xiàn)的非組函數(shù)的字段必須聲明在GROUP BY中。

? 反之,GROUP BY中聲明的字段可以不出現(xiàn)在SELECT中。

結(jié)論2:GROUP BY聲明在FROM后面、WHERE后面、ORDER BY前面、LIMIT前面。

2.4.2 使用WITH ROLLUP
SELECT department_id,AVG(salary)
FROM employees
WHERE department_id > 80
GROUP BY department_id WITH ROLLUP;

注意: 當使用ROLLUP時,不能同時使用ORDER BY子句進行結(jié)果排序,即ROLLUP和ORDER BY是互相排斥的。

2.5. HAVING

2.5.1 基本使用

過濾分組:HAVING子句

  1. 行已經(jīng)被分組。
  2. 使用了聚合函數(shù)。
  3. 滿足HAVING 子句中條件的分組將被顯示。
  4. HAVING 不能單獨使用,必須要跟 GROUP BY 一起使用。
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000 ;

要求

  • 如果過濾條件中使用了聚合函數(shù),則必須使用HAVING來替換WHERE。否則,報錯。
  • 當過濾條件中沒有聚合函數(shù)時,則次過濾條件聲明在WHERE中或HAVING中都可以。但是,建議聲明在WHERE中的執(zhí)行效率高。
  • HAVING必須聲明在GROUP BY 的后面
  • 開發(fā)中,我們使用HAVING的前提是SQL中使用了GROUP BY。
2.5.2 WHERE和HAVING的對比

區(qū)別1:WHERE 可以直接使用表中的字段作為篩選條件,但不能使用分組中的計算函數(shù)作為篩選條件; HAVING 必須要與 GROUP BY 配合使用,可以把分組計算的函數(shù)和分組字段作為篩選條件。

這決定了,在需要對數(shù)據(jù)進行分組統(tǒng)計的時候,HAVING 可以完成 WHERE 不能完成的任務。這是因為, 在查詢語法結(jié)構(gòu)中,WHERE 在 GROUP BY 之前,所以無法對分組結(jié)果進行篩選。HAVING 在 GROUP BY 之 后,可以使用分組字段和分組中的計算函數(shù),對分組的結(jié)果集進行篩選,這個功能是 WHERE 無法完成 的。另外,WHERE排除的記錄不再包括在分組中。

區(qū)別2:如果需要通過連接從關(guān)聯(lián)表中獲取需要的數(shù)據(jù),WHERE 是先篩選后連接,而 HAVING 是先連接 后篩選。

這一點,就決定了在關(guān)聯(lián)查詢中,WHERE 比 HAVING 更高效。因為 WHERE 可以先篩選,用一 個篩選后的較小數(shù)據(jù)集和關(guān)聯(lián)表進行連接,這樣占用的資源比較少,執(zhí)行效率也比較高。HAVING 則需要 先把結(jié)果集準備好,也就是用未被篩選的數(shù)據(jù)集進行關(guān)聯(lián),然后對這個大的數(shù)據(jù)集進行篩選,這樣占用 的資源就比較多,執(zhí)行效率也較低。

小結(jié)如下:

關(guān)鍵字 用法 缺點
WHERE 先篩選數(shù)據(jù)再關(guān)聯(lián),執(zhí)行效率高 不能使用分組中的計算函數(shù)進行篩選
HAVING 可以使用分組中的計算函數(shù) 在最后的結(jié)果集中進行篩選,執(zhí)行效率較低

開發(fā)中的選擇:

WHERE 和 HAVING 也不是互相排斥的,我們可以在一個查詢里面同時使用 WHERE 和 HAVING。包含分組 統(tǒng)計函數(shù)的條件用 HAVING,普通條件用 WHERE。這樣,我們就既利用了 WHERE 條件的高效快速,又發(fā) 揮了 HAVING 可以使用包含分組統(tǒng)計函數(shù)的查詢條件的優(yōu)點。當數(shù)據(jù)量特別大的時候,運行效率會有很 大的差別。

二、視圖

1.視圖概述

  • 視圖是一種 虛擬表 ,本身是不具有數(shù)據(jù)的,占用很少的內(nèi)存空間,它是 SQL 中的一個重要概念。
  • 視圖建立在已有表的基礎上, 視圖賴以建立的這些表稱為基表。
  • 視圖的創(chuàng)建和刪除只影響視圖本身,不影響對應的基表。但是當對視圖中的數(shù)據(jù)進行增加、刪除和修改操作時,數(shù)據(jù)表中的數(shù)據(jù)會相應地發(fā)生變化,反之亦然。
  • 視圖提供數(shù)據(jù)內(nèi)容的語句為 SELECT 語句, 可以將視圖理解為存儲起來的 SELECT 語句
  • 在數(shù)據(jù)庫中,視圖不會保存數(shù)據(jù),數(shù)據(jù)真正保存在數(shù)據(jù)表中。當對視圖中的數(shù)據(jù)進行增加、刪除和修改操作時,數(shù)據(jù)表中的數(shù)據(jù)會相應地發(fā)生變化;反之亦然。
  • 視圖,是向用戶提供基表數(shù)據(jù)的另一種表現(xiàn)形式。通常情況下,小型項目的數(shù)據(jù)庫可以不使用視圖,但是在大型項目中,以及數(shù)據(jù)表比較復雜的情況下,視圖的價值就凸顯出來了,它可以幫助我 們把經(jīng)常查詢的結(jié)果集放到虛擬表中,提升使用效率。理解和使用起來都非常方便。

2.創(chuàng)建視圖

CREATE VIEW 視圖名稱 AS 查詢語句

2.1 創(chuàng)建單表視圖

# 方式一:
CREATE VIEW empvu80
AS
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id = 80;

# 方式二:
CREATE VIEW empsalary8000(emp_id, NAME, monthly_sal) # 小括號內(nèi)字段個數(shù)與SELECT中字段個數(shù)相同
AS
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > 8000;

2.2 創(chuàng)建多表聯(lián)合視圖

CREATE VIEW empview
AS
SELECT employee_id emp_id,last_name NAME,department_name
FROM employees e,departments d
WHERE e.department_id = d.department_id;

CREATE VIEW dept_sum_vu
(name, minsal, maxsal, avgsal)
AS
SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;

2.3 基于視圖創(chuàng)建視圖

當我們創(chuàng)建好一張視圖之后,還可以在它的基礎上繼續(xù)創(chuàng)建視圖。
舉例:聯(lián)合“emp_dept”視圖和“emp_year_salary”視圖查詢員工姓名、部門名稱、年薪信息創(chuàng)建 “emp_dept_ysalary”視圖。

CREATE VIEW emp_dept_ysalary
AS
SELECT emp_dept.ename,dname,year_salary
FROM emp_dept INNER JOIN emp_year_salary
ON emp_dept.ename = emp_year_salary.ename;

3.更新視圖的數(shù)據(jù)

3.1 一般情況

MySQL支持使用INSERT、UPDATE和DELETE語句對視圖中的數(shù)據(jù)進行插入、更新和刪除操作。當視圖中的 數(shù)據(jù)發(fā)生變化時,數(shù)據(jù)表中的數(shù)據(jù)也會發(fā)生變化,反之亦然。

舉例:UPDATE操作

UPDATE emp_tel SET tel = '13789091234' WHERE ename = '孫洪亮';

舉例:DELETE操作

 DELETE FROM emp_tel WHERE ename = '孫洪亮';

3.2 不可更新的視圖

要使視圖可更新,視圖中的行和底層基本表中的行之間必須存在 一對一 的關(guān)系。另外當視圖定義出現(xiàn)如下情況時,視圖不支持更新操作:

  • 在定義視圖的時候指定了“ALGORITHM = TEMPTABLE”,視圖將不支持INSERT和DELETE操作;
  • 視圖中不包含基表中所有被定義為非空又未指定默認值的列,視圖將不支持INSERT操作;
  • 在定義視圖的SELECT語句中使用了 JOIN聯(lián)合查詢 ,視圖將不支持INSERT和DELETE操作;
  • 在定義視圖的SELECT語句后的字段列表中使用了 數(shù)學表達式 或 子查詢 ,視圖將不支持INSERT,也 不支持UPDATE使用了數(shù)學表達式、子查詢的字段值;
  • 在定義視圖的SELECT語句后的字段列表中使用 DISTINCT 、 聚合函數(shù) 、 GROUP BY 、 HAVING 、 UNION 等,視圖將不支持INSERT、UPDATE、DELETE;
  • 在定義視圖的SELECT語句中包含了子查詢,而子查詢中引用了FROM后面的表,視圖將不支持 INSERT、UPDATE、DELETE;
  • 視圖定義基于一個 不可更新視圖 ; 常量視圖。

雖然可以更新視圖數(shù)據(jù),但總的來說,視圖作為虛擬表 ,主要用于方便查詢 ,不建議更新視圖的數(shù)據(jù)。對視圖數(shù)據(jù)的更改,都是通過對實際數(shù)據(jù)表里數(shù)據(jù)的操作來完成的。

4. 修改、刪除視圖

4.1 修改視圖

方式1:使用CREATE OR REPLACE VIEW 子句修改視圖

CREATE OR REPLACE VIEW empvu80
(id_number, name, sal, department_id)
AS
SELECT employee_id, first_name || ' ' || last_name, salary, department_id
FROM employees
WHERE department_id = 80;

說明:CREATE VIEW 子句中各列的別名應和子查詢中各列相對應。

方式2:ALTER VIEW

修改視圖的語法是:

ALTER VIEW 視圖名稱
AS
查詢語句

4.2 刪除視圖

  • 刪除視圖只是刪除視圖的定義,并不會刪除基表的數(shù)據(jù)。
  • 刪除視圖的語法是:
DROP VIEW IF EXISTS 視圖名稱;
  • 舉例:
DROP VIEW empvu80;
  • 說明:基于視圖a、b創(chuàng)建了新的視圖c,如果將視圖a或者視圖b刪除,會導致視圖c的查詢失敗。這 樣的視圖c需要手動刪除或修改,否則影響使用。

5. 總結(jié)

5.1 優(yōu)點

1. 操作簡單

將經(jīng)常使用的查詢操作定義為視圖,可以使開發(fā)人員不需要關(guān)心視圖對應的數(shù)據(jù)表的結(jié)構(gòu)、表與表之間的關(guān)聯(lián)關(guān)系,也不需要關(guān)心數(shù)據(jù)表之間的業(yè)務邏輯和查詢條件,而只需要簡單地操作視圖即可,極大簡化了開發(fā)人員對數(shù)據(jù)庫的操作。

2. 減少數(shù)據(jù)冗余

視圖跟實際數(shù)據(jù)表不一樣,它存儲的是查詢語句。所以,在使用的時候,我們要通過定義視圖的查詢語句來獲取結(jié)果集。而視圖本身不存儲數(shù)據(jù),不占用數(shù)據(jù)存儲的資源,減少了數(shù)據(jù)冗余。

3. 數(shù)據(jù)安全

MySQL將用戶對數(shù)據(jù)的 訪問限制 在某些數(shù)據(jù)的結(jié)果集上,而這些數(shù)據(jù)的結(jié)果集可以使用視圖來實現(xiàn)。用戶不必直接查詢或操作數(shù)據(jù)表。這也可以理解為視圖具有 隔離性 。視圖相當于在用戶和實際的數(shù)據(jù)表之間加了一層虛擬表。

同時,MySQL可以根據(jù)權(quán)限將用戶對數(shù)據(jù)的訪問限制在某些視圖上,用戶不需要查詢數(shù)據(jù)表,可以直接通過視圖獲取數(shù)據(jù)表中的信息。這在一定程度上保障了數(shù)據(jù)表中數(shù)據(jù)的安全性。

4. 適應靈活多變的需求

當業(yè)務系統(tǒng)的需求發(fā)生變化后,如果需要改動數(shù)據(jù)表的結(jié)構(gòu),則工作量相對較 大,可以使用視圖來減少改動的工作量。這種方式在實際工作中使用得比較多。

5. 能夠分解復雜的查詢邏輯

數(shù)據(jù)庫中如果存在復雜的查詢邏輯,則可以將問題進行分解,創(chuàng)建多個視圖 獲取數(shù)據(jù),再將創(chuàng)建的多個視圖結(jié)合起來,完成復雜的查詢邏輯。

5.2 不足

如果我們在實際數(shù)據(jù)表的基礎上創(chuàng)建了視圖,那么,如果實際數(shù)據(jù)表的結(jié)構(gòu)變更了,我們就需要及時對相關(guān)的視圖進行相應的維護。特別是嵌套的視圖(就是在視圖的基礎上創(chuàng)建視圖),維護會變得比較復雜, 可讀性不好 ,容易變成系統(tǒng)的潛在隱患。因為創(chuàng)建視圖的 SQL 查詢可能會對字段重命名,也可能包含復雜的邏輯,這些都會增加維護的成本。

實際項目中,如果視圖過多,會導致數(shù)據(jù)庫維護成本的問題。

所以,在創(chuàng)建視圖的時候,你要結(jié)合實際項目需求,綜合考慮視圖的優(yōu)點和不足,這樣才能正確使用視圖,使系統(tǒng)整體達到最優(yōu)。

三、存儲過程

MySQL從5.0版本開始支持存儲過程和函數(shù)。存儲過程和函數(shù)能夠?qū)碗s的SQL邏輯封裝在一起,應用程 序無須關(guān)注存儲過程和函數(shù)內(nèi)部復雜的SQL邏輯,而只需要簡單地調(diào)用存儲過程和函數(shù)即可。

1. 存儲過程概述

1.1 理解

**含義:**存儲過程的英文是 Stored Procedure 。它的思想很簡單,就是一組經(jīng)過 預先編譯的 SQL 語句 的封裝。

執(zhí)行過程:存儲過程預先存儲在 MySQL 服務器上,需要執(zhí)行的時候,客戶端只需要向服務器端發(fā)出調(diào)用存儲過程的命令,服務器端就可以把預先存儲好的這一系列 SQL 語句全部執(zhí)行。

好處:

  • 1、簡化操作,提高了sql語句的重用性,減少了開發(fā)程序員的壓力。
  • 2、減少操作過程中的失誤,提高效率。
  • 3、減少網(wǎng)絡傳輸量(客戶端不需要把所有的 SQL 語句通過網(wǎng)絡發(fā)給服務器)。
  • 4、減少了 SQL 語句暴露在 網(wǎng)上的風險,也提高了數(shù)據(jù)查詢的安全性。

和視圖、函數(shù)的對比:

它和視圖有著同樣的優(yōu)點,清晰、安全,還可以減少網(wǎng)絡傳輸量。不過它和視圖不同,視圖是虛擬表 ,通常不對底層數(shù)據(jù)表直接操作,而存儲過程是程序化的 SQL,可以 直接操作底層數(shù)據(jù)表 ,相比于面向集合的操作方式,能夠?qū)崿F(xiàn)一些更復雜的數(shù)據(jù)處理。

一旦存儲過程被創(chuàng)建出來,使用它就像使用函數(shù)一樣簡單,我們直接通過調(diào)用存儲過程名即可。相較于函數(shù),存儲過程是 沒有返回值 的。

1.2 分類

存儲過程的參數(shù)類型可以是IN、OUT和INOUT。根據(jù)這點分類如下:

1、沒有參數(shù)(無參數(shù)無返回)

2、僅僅帶 IN 類型(有參數(shù)無返回)

3、僅僅帶 OUT 類型(無參數(shù)有返回)

4、既帶 IN 又帶 OUT(有參數(shù)有返回)

5、帶 INOUT(有參數(shù)有返回)

注意:IN、OUT、INOUT 都可以在一個存儲過程中帶多個。

2. 創(chuàng)建存儲過程

2.1 語法分析

語法:

CREATE PROCEDURE 存儲過程名(IN|OUT|INOUT 參數(shù)名 參數(shù)類型,...)
[characteristics ...]
BEGIN
存儲過程體
END

說明:

1、參數(shù)前面的符號的意思

  • IN :當前參數(shù)為輸入?yún)?shù),也就是表示入?yún)ⅲ?/p>

    存儲過程只是讀取這個參數(shù)的值。如果沒有定義參數(shù)種類, 默認就是 IN ,表示輸入?yún)?shù)。

  • OUT :當前參數(shù)為輸出參數(shù),也就是表示出參;

    執(zhí)行完成之后,調(diào)用這個存儲過程的客戶端或者應用程序就可以讀取這個參數(shù)返回的值了。

  • INOUT :當前參數(shù)既可以為輸入?yún)?shù),也可以為輸出參數(shù)。

2、形參類型可以是 MySQL數(shù)據(jù)庫中的任意類型。

3、characteristics 表示創(chuàng)建存儲過程時指定的對存儲過程的約束條件,其取值信息如下:

LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
  • LANGUAGE SQL :說明存儲過程執(zhí)行體是由SQL語句組成的,當前系統(tǒng)支持的語言為SQL。

  • [NOT] DETERMINISTIC :指明存儲過程執(zhí)行的結(jié)果是否確定。DETERMINISTIC表示結(jié)果是確定 的。每次執(zhí)行存儲過程時,相同的輸入會得到相同的輸出。NOT DETERMINISTIC表示結(jié)果是不確定 的,相同的輸入可能得到不同的輸出。如果沒有指定任意一個值,默認為NOT DETERMINISTIC。

  • { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } :指明子程序使 用SQL語句的限制。

    • CONTAINS SQL表示當前存儲過程的子程序包含SQL語句,但是并不包含讀寫數(shù)據(jù)的SQL語句;
    • NO SQL表示當前存儲過程的子程序中不包含任何SQL語句;
    • READS SQL DATA表示當前存儲過程的子程序中包含讀數(shù)據(jù)的SQL語句;
    • MODIFIES SQL DATA表示當前存儲過程的子程序中包含寫數(shù)據(jù)的SQL語句。
    • 默認情況下,系統(tǒng)會指定為CONTAINS SQL。
  • SQL SECURITY { DEFINER | INVOKER } :執(zhí)行當前存儲過程的權(quán)限,即指明哪些用戶能夠執(zhí)行當前存儲過程。

    • DEFINER 表示只有當前存儲過程的創(chuàng)建者或者定義者才能執(zhí)行當前存儲過程;
    • INVOKER 表示擁有當前存儲過程的訪問權(quán)限的用戶能夠執(zhí)行當前存儲過程。
  • COMMENT ‘string’ :注釋信息,可以用來描述存儲過程。

4、存儲過程體中可以有多條 SQL 語句,如果僅僅一條SQL 語句,則可以省略 BEGIN 和 END

1. BEGIN…END:BEGIN…END 中間包含了多個語句,每個語句都以(;)號為結(jié)束符。
2. DECLARE:DECLARE 用來聲明變量,使用的位置在于 BEGIN…END 語句中間,而且需要在其他語句使用之前進
行變量的聲明。
3. SET:賦值語句,用于對變量進行賦值。
4. SELECT… INTO:把從數(shù)據(jù)表中查詢的結(jié)果存放到變量中,也就是為變量賦值。

5、需要設置新的結(jié)束標記

DELIMITER 新的結(jié)束標記

因為MySQL默認的語句結(jié)束符號為分號‘;’。為了避免與存儲過程中SQL語句結(jié)束符相沖突,需要使用 DELIMITER改變存儲過程的結(jié)束符。

比如:“DELIMITER //”語句的作用是將MySQL的結(jié)束符設置為//,并以“END //”結(jié)束存儲過程。存儲過程定 義完畢之后再使用“DELIMITER ;”恢復默認結(jié)束符。DELIMITER也可以指定其他符號作為結(jié)束符。

當使用DELIMITER命令時,應該避免使用反斜杠(‘\’)字符,因為反斜線是MySQL的轉(zhuǎn)義字符。

示例:

DELIMITER $
CREATE PROCEDURE 存儲過程名(IN|OUT|INOUT 參數(shù)名 參數(shù)類型,...)
[characteristics ...]
BEGIN
sql語句1;
sql語句2;
END $

2.2 代碼舉例

舉例1:創(chuàng)建存儲過程select_all_data(),查看 emps 表的所有數(shù)據(jù)

DELIMITER $
CREATE PROCEDURE select_all_data()
BEGIN
SELECT * FROM emps;
END $
DELIMITER ;

舉例2:創(chuàng)建存儲過程avg_employee_salary(),返回所有員工的平均工資

DELIMITER //
CREATE PROCEDURE avg_employee_salary ()
BEGIN
SELECT AVG(salary) AS avg_salary FROM emps;
END //
DELIMITER ;

3. 調(diào)用存儲過程

3.1 調(diào)用格式

存儲過程有多種調(diào)用方法。存儲過程必須使用CALL語句調(diào)用,并且存儲過程和數(shù)據(jù)庫相關(guān),如果要執(zhí)行其他數(shù)據(jù)庫中的存儲過程,需要指定數(shù)據(jù)庫名稱,例如CALL dbname.procname。

CALL 存儲過程名(實參列表)

格式:

1、調(diào)用in模式的參數(shù):

CALL sp1('值');

2、調(diào)用out模式的參數(shù):

SET @name;
CALL sp1(@name);
SELECT @name;

3、調(diào)用inout模式的參數(shù):

SET @name=值;
CALL sp1(@name);
SELECT @name;

3.2 代碼舉例

舉例1:

DELIMITER //
CREATE PROCEDURE CountProc(IN sid INT,OUT num INT)
BEGIN
SELECT COUNT(*) INTO num FROM fruits
WHERE s_id = sid;
END //
DELIMITER ;

調(diào)用存儲過程:

CALL CountProc (101, @num);

查看返回結(jié)果:

SELECT @num;

**舉例2:**創(chuàng)建存儲過程,實現(xiàn)累加運算,計算 1+2+…+n 等于多少。具體的代碼如下:

DELIMITER //
CREATE PROCEDURE `add_num`(IN n INT)
BEGIN
DECLARE i INT;
DECLARE sum INT;
SET i = 1;
SET sum = 0;
WHILE i <= n DO
SET sum = sum + i;
SET i = i +1;
END WHILE;
SELECT sum;
END //
DELIMITER ;

直接使用 CALL add_num(50); 即可。這里我傳入的參數(shù)為 50,也就是統(tǒng)計 1+2+…+50 的積累之和。

3.3 如何調(diào)試

在 MySQL 中,存儲過程不像普通的編程語言(比如 VC++、Java 等)那樣有專門的集成開發(fā)環(huán)境。因 此,你可以通過 SELECT 語句,把程序執(zhí)行的中間結(jié)果查詢出來,來調(diào)試一個 SQL 語句的正確性。調(diào)試 成功之后,把 SELECT 語句后移到下一個 SQL 語句之后,再調(diào)試下一個 SQL 語句。這樣 逐步推進 ,就可以完成對存儲過程中所有操作的調(diào)試了。當然,你也可以把存儲過程中的 SQL 語句復制出來,逐段單獨 調(diào)試。

4. 存儲函數(shù)的使用

4.1 語法分析

學過的函數(shù):LENGTH、SUBSTR、CONCAT等

語法格式:

CREATE FUNCTION 函數(shù)名(參數(shù)名 參數(shù)類型,...)
RETURNS 返回值類型
[characteristics ...]
BEGIN
函數(shù)體 #函數(shù)體中肯定有 RETURN 語句
END

說明:

1、參數(shù)列表:指定參數(shù)為IN、OUT或INOUT只對PROCEDURE是合法的,F(xiàn)UNCTION中總是默認為IN參數(shù)。

2、RETURNS type 語句表示函數(shù)返回數(shù)據(jù)的類型; RETURNS子句只能對FUNCTION做指定,對函數(shù)而言這是 強制 的。它用來指定函數(shù)的返回類型,而且函 數(shù)體必須包含一個 RETURN value 語句。

3、characteristic 創(chuàng)建函數(shù)時指定的對函數(shù)的約束。取值與創(chuàng)建存儲過程時相同,這里不再贅述。

4、函數(shù)體也可以用BEGIN…END來表示SQL代碼的開始和結(jié)束。如果函數(shù)體只有一條語句,也可以省略 BEGIN…END。

4.2 調(diào)用存儲函數(shù)

在MySQL中,存儲函數(shù)的使用方法與MySQL內(nèi)部函數(shù)的使用方法是一樣的。換言之,用戶自己定義的存儲函數(shù)與MySQL內(nèi)部函數(shù)是一個性質(zhì)的。區(qū)別在于,存儲函數(shù)是 用戶自己定義 的,而內(nèi)部函數(shù)是MySQL 的 開發(fā)者定義 的。

SELECT 函數(shù)名(實參列表)

4.3 代碼舉例

舉例1:

創(chuàng)建存儲函數(shù),名稱為email_by_name(),參數(shù)定義為空,該函數(shù)查詢Abel的email,并返回,數(shù)據(jù)類型為字符串型。

DELIMITER //
CREATE FUNCTION email_by_name()
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
END //
DELIMITER ;

調(diào)用:

SELECT email_by_name();

舉例2:

創(chuàng)建存儲函數(shù),名稱為email_by_id(),參數(shù)傳入emp_id,該函數(shù)查詢emp_id的email,并返回,數(shù)據(jù)類型 為字符串型。

DELIMITER //
CREATE FUNCTION email_by_id(emp_id INT)
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
RETURN (SELECT email FROM employees WHERE employee_id = emp_id);
END //
DELIMITER ;

調(diào)用:

SET @emp_id = 102;
SELECT email_by_id(@emp_id);

注意:

若在創(chuàng)建存儲函數(shù)中報錯“ you might want to use the less safe log_bin_trust_function_creators variable ”,有兩種處理方法:

  • 方式1:

    加上必要的函數(shù)特性“[NOT] DETERMINISTIC”和“{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}”

  • 方式2:

SET GLOBAL log_bin_trust_function_creators = 1;

4.4 對比存儲函數(shù)與存儲過程

關(guān)鍵字 調(diào)用語法 返回值 應用場景
存儲過程 PROCEDURE CALL 存儲過程() 理解為有0個或多個 一般用于更新
存儲函數(shù) FUNCTION SELECT 函數(shù) () 只能是一個 一般用于查詢結(jié)果為一個值并返回時

此外,存儲函數(shù)可以放在查詢語句中使用,存儲過程不行。反之,存儲過程的功能更加強大,包括能夠 執(zhí)行對表的操作(比如創(chuàng)建表,刪除表等)和事務操作,這些功能是存儲函數(shù)不具備的。

5. 存儲過程和函數(shù)的查看、修改、刪除

5.1 查看

創(chuàng)建完之后,怎么知道我們創(chuàng)建的存儲過程、存儲函數(shù)是否成功了呢?

MySQL存儲了存儲過程和函數(shù)的狀態(tài)信息,用戶可以使用SHOW STATUS語句或SHOW CREATE語句來查 看,也可直接從系統(tǒng)的information_schema數(shù)據(jù)庫中查詢。這里介紹3種方法。

  1. 使用SHOW CREATE語句查看存儲過程和函數(shù)的創(chuàng)建信息
SHOW CREATE {PROCEDURE | FUNCTION} 存儲過程名或函數(shù)名
  1. 使用SHOW STATUS語句查看存儲過程和函數(shù)的狀態(tài)信息
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
  1. 從information_schema.Routines表中查看存儲過程和函數(shù)的信息

MySQL中存儲過程和函數(shù)的信息存儲在information_schema數(shù)據(jù)庫下的Routines表中。可以通過查詢該表的記錄來查詢存儲過程和函數(shù)的信息。其基本語法形式如下:

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='存儲過程或函數(shù)的名' [AND ROUTINE_TYPE = {'PROCEDURE|FUNCTION'}];

說明:如果在MySQL數(shù)據(jù)庫中存在存儲過程和函數(shù)名稱相同的情況,最好指定ROUTINE_TYPE查詢條件來 指明查詢的是存儲過程還是函數(shù)。

5.2 修改

修改存儲過程或函數(shù),不影響存儲過程或函數(shù)功能,只是修改相關(guān)特性。使用ALTER語句實現(xiàn)。

ALTER {PROCEDURE | FUNCTION} 存儲過程或函數(shù)的名 [characteristic ...]

其中,characteristic指定存儲過程或函數(shù)的特性,其取值信息與創(chuàng)建存儲過程、函數(shù)時的取值信息略有不同。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
  • CONTAINS SQL ,表示子程序包含SQL語句,但不包含讀或?qū)憯?shù)據(jù)的語句。

  • NO SQL ,表示子程序中不包含SQL語句。

  • READS SQL DATA ,表示子程序中包含讀數(shù)據(jù)的語句。

  • MODIFIES SQL DATA ,表示子程序中包含寫數(shù)據(jù)的語句。

  • SQL SECURITY { DEFINER | INVOKER } ,指明誰有權(quán)限來執(zhí)行。

    • DEFINER ,表示只有定義者自己才能夠執(zhí)行。
    • INVOKER ,表示調(diào)用者可以執(zhí)行。
  • COMMENT ‘string’ ,表示注釋信息。

修改存儲過程使用ALTER PROCEDURE語句,修改存儲函數(shù)使用ALTER FUNCTION語句。但是,這兩 個語句的結(jié)構(gòu)是一樣的,語句中的所有參數(shù)也是一樣的。

5.3 刪除

刪除存儲過程和函數(shù),可以使用DROP語句,其語法結(jié)構(gòu)如下:

DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存儲過程或函數(shù)的名

6. 關(guān)于存儲過程使用的爭議

6.1 優(yōu)點

1、存儲過程可以一次編譯多次使用。存儲過程只在創(chuàng)建時進行編譯,之后的使用都不需要重新編譯, 這就提升了 SQL 的執(zhí)行效率。

2、可以減少開發(fā)工作量。將代碼 封裝 成模塊,實際上是編程的核心思想之一,這樣可以把復雜的問題 拆解成不同的模塊,然后模塊之間可以 重復使用 ,在減少開發(fā)工作量的同時,還能保證代碼的結(jié)構(gòu)清 晰。

3、存儲過程的安全性強。我們在設定存儲過程的時候可以 設置對用戶的使用權(quán)限 ,這樣就和視圖一樣具 有較強的安全性。

4、可以減少網(wǎng)絡傳輸量。因為代碼封裝到存儲過程中,每次使用只需要調(diào)用存儲過程即可,這樣就減 少了網(wǎng)絡傳輸量。

5、良好的封裝性。在進行相對復雜的數(shù)據(jù)庫操作時,原本需要使用一條一條的 SQL 語句,可能要連接 多次數(shù)據(jù)庫才能完成的操作,現(xiàn)在變成了一次存儲過程,只需要 連接一次即可 。

6.2 缺點

阿里開發(fā)規(guī)范 【強制】禁止使用存儲過程,存儲過程難以調(diào)試和擴展,更沒有移植性。

1、可移植性差。存儲過程不能跨數(shù)據(jù)庫移植,比如在 MySQL、Oracle 和 SQL Server 里編寫的存儲過 程,在換成其他數(shù)據(jù)庫時都需要重新編寫。

2、調(diào)試困難。只有少數(shù) DBMS 支持存儲過程的調(diào)試。對于復雜的存儲過程來說,開發(fā)和維護都不容 易。雖然也有一些第三方工具可以對存儲過程進行調(diào)試,但要收費。

3、存儲過程的版本管理很困難。比如數(shù)據(jù)表索引發(fā)生變化了,可能會導致存儲過程失效。我們在開發(fā) 軟件的時候往往需要進行版本管理,但是存儲過程本身沒有版本控制,版本迭代更新的時候很麻煩。

4、它不適合高并發(fā)的場景。高并發(fā)的場景需要減少數(shù)據(jù)庫的壓力,有時數(shù)據(jù)庫會采用分庫分表的方式,而且對可擴展性要求很高,在這種情況下,存儲過程會變得難以維護, 增加數(shù)據(jù)庫的壓力 ,顯然就不適用了。

6.3 小結(jié)

存儲過程既方便,又有局限性。盡管不同的公司對存儲過程的態(tài)度不一,但是對于我們開發(fā)人員來說, 不論怎樣,掌握存儲過程都是必備的技能之一。

四、觸發(fā)器

在實際開發(fā)中,我們經(jīng)常會遇到這樣的情況:有 2 個或者多個相互關(guān)聯(lián)的表,如 商品信息 和 庫存信息 分別存放在 2 個不同的數(shù)據(jù)表中,我們在添加一條新商品記錄的時候,為了保證數(shù)據(jù)的完整性,必須同時 在庫存表中添加一條庫存記錄。

這樣一來,我們就必須把這兩個關(guān)聯(lián)的操作步驟寫到程序里面,而且要用事務包裹起來,確保這兩個操作成為一個 原子操作 ,要么全部執(zhí)行,要么全部不執(zhí)行。要是遇到特殊情況,可能還需要對數(shù)據(jù)進行手動維護,這樣就很容易忘記其中的一步 ,導致數(shù)據(jù)缺失。

這個時候,咱們可以使用觸發(fā)器。你可以創(chuàng)建一個觸發(fā)器,讓商品信息數(shù)據(jù)的插入操作自動觸發(fā)庫存數(shù)據(jù)的插入操作。這樣一來,就不用擔心因為忘記添加庫存數(shù)據(jù)而導致的數(shù)據(jù)缺失了。

1. 觸發(fā)器概述

觸發(fā)器是由 事件來觸發(fā) 某個操作,這些事件包括 INSERT 、 UPDATE 、 DELETE 事件。所謂事件就是指用戶的動作或者觸發(fā)某項行為。如果定義了觸發(fā)程序,當數(shù)據(jù)庫執(zhí)行這些語句時候,就相當于事件發(fā)生 了,就會 自動 激發(fā)觸發(fā)器執(zhí)行相應的操作。

當對數(shù)據(jù)表中的數(shù)據(jù)執(zhí)行插入、更新和刪除操作,需要自動執(zhí)行一些數(shù)據(jù)庫邏輯時,可以使用觸發(fā)器來實現(xiàn)。

2. 觸發(fā)器的創(chuàng)建

2.1 語法

CREATE TRIGGER 觸發(fā)器名稱
{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
FOR EACH ROW
觸發(fā)器執(zhí)行的語句塊

說明:

  • 表名 :表示觸發(fā)器監(jiān)控的對象。
  • BEFORE|AFTER :表示觸發(fā)的時間。BEFORE 表示在事件之前觸發(fā);AFTER 表示在事件之后觸發(fā)。
  • INSERT|UPDATE|DELETE :表示觸發(fā)的事件。
    • INSERT 表示插入記錄時觸發(fā);
    • UPDATE 表示更新記錄時觸發(fā);
    • DELETE 表示刪除記錄時觸發(fā)。
  • 觸發(fā)器執(zhí)行的語句塊 :可以是單條SQL語句,也可以是由BEGIN…END結(jié)構(gòu)組成的復合語句塊。

2.2 代碼舉例

舉例1:

  1. 創(chuàng)建數(shù)據(jù)表:
CREATE TABLE test_trigger (
id INT PRIMARY KEY AUTO_INCREMENT,
t_note VARCHAR(30)
);

CREATE TABLE test_trigger_log (
id INT PRIMARY KEY AUTO_INCREMENT,
t_log VARCHAR(30)
);
  1. 創(chuàng)建觸發(fā)器:創(chuàng)建名稱為before_insert的觸發(fā)器,向test_trigger數(shù)據(jù)表插入數(shù)據(jù)之前,向 test_trigger_log數(shù)據(jù)表中插入before_insert的日志信息。
DELIMITER //
CREATE TRIGGER before_insert
BEFORE INSERT ON test_trigger
FOR EACH ROW
BEGIN
    INSERT INTO test_trigger_log (t_log)
    VALUES('before_insert');
END //
DELIMITER ;
  1. 向test_trigger數(shù)據(jù)表中插入數(shù)據(jù)
INSERT INTO test_trigger (t_note) VALUES ('測試 BEFORE INSERT 觸發(fā)器');
  1. 查看test_trigger_log數(shù)據(jù)表中的數(shù)據(jù)
mysql> SELECT * FROM test_trigger_log;
+----+---------------+
| id | t_log |
+----+---------------+
| 1 | before_insert |
+----+---------------+
1 row in set (0.00 sec)

舉例2:

定義觸發(fā)器“salary_check_trigger”,基于員工表“employees”的INSERT事件,在INSERT之前檢查 將要添加的新員工薪資是否大于他領(lǐng)導的薪資,如果大于領(lǐng)導薪資,則報sqlstate_value為’HY000’的錯 誤,從而使得添加失敗。

DELIMITER //
CREATE TRIGGER salary_check_trigger
BEFORE INSERT ON employees FOR EACH ROW
BEGIN
    DECLARE mgrsalary DOUBLE;
    SELECT salary INTO mgrsalary FROM employees WHERE employee_id = NEW.manager_id;
    IF NEW.salary > mgrsalary THEN
    	SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = '薪資高于領(lǐng)導薪資錯誤';
    END IF;
END //
DELIMITER ;

上面觸發(fā)器聲明過程中的NEW關(guān)鍵字代表INSERT添加語句的新記錄。

3. 查看、刪除觸發(fā)器

3.1 查看觸發(fā)器

查看觸發(fā)器是查看數(shù)據(jù)庫中已經(jīng)存在的觸發(fā)器的定義、狀態(tài)和語法信息等。

方式1:查看當前數(shù)據(jù)庫的所有觸發(fā)器的定義

SHOW TRIGGERS\G

方式2:查看當前數(shù)據(jù)庫中某個觸發(fā)器的定義

SHOW CREATE TRIGGER 觸發(fā)器名

方式3:從系統(tǒng)庫information_schema的TRIGGERS表中查詢“salary_check_trigger”觸發(fā)器的信息。

SELECT * FROM information_schema.TRIGGERS;

3.2 刪除觸發(fā)器

觸發(fā)器也是數(shù)據(jù)庫對象,刪除觸發(fā)器也用DROP語句,語法格式如下:

DROP TRIGGER IF EXISTS 觸發(fā)器名稱;

4. 觸發(fā)器的優(yōu)缺點

4.1 優(yōu)點

1、觸發(fā)器可以確保數(shù)據(jù)的完整性。

假設我們用 進貨單頭表 (demo.importhead)來保存進貨單的總體信息,包括進貨單編號、供貨商編號、倉庫編號、總計進貨數(shù)量、總計進貨金額和驗收日期。

listnumber (進貨單編號) supplierid (進貨商編號) stockid (參庫編號) quantity (總計數(shù)量) importvalue (總計金額) confirmationdate (驗收日期)

用進貨單明細表 (demo.importdetails)來保存進貨商品的明細,包括進貨單編號、商品編號、進貨數(shù) 量、進貨價格和進貨金額。

listnumber (進貨單編號) itemnumber (商品編號) quantity (進貨數(shù)量) importprice (進貨價格) importvalue (進貨金額)

每當我們錄入、刪除和修改一條進貨單明細數(shù)據(jù)的時候,進貨單明細表里的數(shù)據(jù)就會發(fā)生變動。這個時候,在進貨單頭表中的總計數(shù)量和總計金額就必須重新計算,否則,進貨單頭表中的總計數(shù)量和總計金 額就不等于進貨單明細表中數(shù)量合計和金額合計了,這就是數(shù)據(jù)不一致。

為了解決這個問題,我們就可以使用觸發(fā)器,規(guī)定每當進貨單明細表有數(shù)據(jù)插入、修改和刪除的操作 時,自動觸發(fā) 2 步操作:

1)重新計算進貨單明細表中的數(shù)量合計和金額合計;

2)用第一步中計算出來的值更新進貨單頭表中的合計數(shù)量與合計金額。

這樣一來,進貨單頭表中的合計數(shù)量與合計金額的值,就始終與進貨單明細表中計算出來的合計數(shù)量與 合計金額的值相同,數(shù)據(jù)就是一致的,不會互相矛盾。

2、觸發(fā)器可以幫助我們記錄操作日志。

利用觸發(fā)器,可以具體記錄什么時間發(fā)生了什么。比如,記錄修改會員儲值金額的觸發(fā)器,就是一個很好的例子。這對我們還原操作執(zhí)行時的具體場景,更好地定位問題原因很有幫助。

3、觸發(fā)器還可以用在操作數(shù)據(jù)前,對數(shù)據(jù)進行合法性檢查。

比如,超市進貨的時候,需要庫管錄入進貨價格。但是,人為操作很容易犯錯誤,比如說在錄入數(shù)量的時候,把條形碼掃進去了;錄入金額的時候,看串了行,錄入的價格遠超售價,導致賬面上的巨虧…… 這些都可以通過觸發(fā)器,在實際插入或者更新操作之前,對相應的數(shù)據(jù)進行檢查,及時提示錯誤,防止錯誤數(shù)據(jù)進入系統(tǒng)。

4.2 缺點

1、觸發(fā)器最大的一個問題就是可讀性差。

因為觸發(fā)器存儲在數(shù)據(jù)庫中,并且由事件驅(qū)動,這就意味著觸發(fā)器有可能不受應用層的控制 。這對系統(tǒng)維護是非常有挑戰(zhàn)的。

2、相關(guān)數(shù)據(jù)的變更,可能會導致觸發(fā)器出錯。

特別是數(shù)據(jù)表結(jié)構(gòu)的變更,都可能會導致觸發(fā)器出錯,進而影響數(shù)據(jù)操作的正常運行。這些都會由于觸發(fā)器本身的隱蔽性,影響到應用中錯誤原因排查的效率。

4.3 注意點

注意,如果在子表中定義了外鍵約束,并且外鍵指定了ON UPDATE/DELETE CASCADE/SET NULL子句,此時修改父表被引用的鍵值或刪除父表被引用的記錄行時,也會引起子表的修改和刪除操作,此時基于子表的UPDATE和DELETE語句定義的觸發(fā)器并不會被激活。

例如:基于子表員工表(t_employee)的DELETE語句定義了觸發(fā)器t1,而子表的部門編號(did)字段定義了外鍵約束引用了父表部門表(t_department)的主鍵列部門編號(did),并且該外鍵加了“ON DELETE SET NULL”子句,那么如果此時刪除父表部門表(t_department)在子表員工表(t_employee) 有匹配記錄的部門記錄時,會引起子表員工表(t_employee)匹配記錄的部門編號(did)修改為NULL, mysql> update demo.membermaster set memberdeposit=20 where memberid = 2; ERROR 1054 (42S22): Unknown column ‘a(chǎn)a’ in ‘field list’ 但是此時不會激活觸發(fā)器t1。只有直接對子表員工表(t_employee)執(zhí)行DELETE語句時才會激活觸發(fā)器 t1。

? 原創(chuàng)不易,還希望各位大佬支持一下 \textcolor{blue}{原創(chuàng)不易,還希望各位大佬支持一下} 原創(chuàng)不易,還希望各位大佬支持一下

?? 點贊,你的認可是我創(chuàng)作的動力! \textcolor{green}{點贊,你的認可是我創(chuàng)作的動力!} 點贊,你的認可是我創(chuàng)作的動力!

?? 收藏,你的青睞是我努力的方向! \textcolor{green}{收藏,你的青睞是我努力的方向!} 收藏,你的青睞是我努力的方向!

?? 評論,你的意見是我進步的財富! \textcolor{green}{評論,你的意見是我進步的財富!} 評論,你的意見是我進步的財富!
文章來源地址http://www.zghlxwxcb.cn/news/detail-405937.html

到了這里,關(guān)于MySQL函數(shù)、視圖、存儲過程及觸發(fā)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 存儲過程、觸發(fā)器、游標、視圖、自定義函數(shù) 字段類型、字段可空、統(tǒng)計字段、邏輯刪除 權(quán)限系統(tǒng)數(shù)據(jù)庫&無限極類別設計

    在數(shù)據(jù)庫設計中,存儲過程、觸發(fā)器、游標、視圖、自定義函數(shù)、字段類型、字段可空、統(tǒng)計字段、邏輯刪除以及權(quán)限系統(tǒng)和無限級類別設計都是重要的概念。下面我將逐一解釋這些概念,并提供相關(guān)的設計建議。 存儲過程 (Stored Procedure) 定義 :存儲過程是一組為了完成特定

    2024年03月09日
    瀏覽(102)
  • MySQL 存儲過程&觸發(fā)器&事務

    存儲過程(Stored Procedure),是為了完成特定功能的SQL語句集。 存儲過程可以理解為shell腳本這類型的命令集輸出工具,但是在底層,存儲過程擁有更多的優(yōu)點: 語言的靈活性跟功能性更強 ,在原有基礎之上可以插入 控制語句、循環(huán)語句等 讓SQL語句的功能更強,能夠完成更

    2024年02月04日
    瀏覽(21)
  • MySQL存儲過程和觸發(fā)器

    存儲過程和觸發(fā)器是數(shù)據(jù)庫中用于執(zhí)行特定任務的兩種重要的數(shù)據(jù)庫對象。它們由SQL語句組成,被預先編譯并存儲在數(shù)據(jù)庫中,可以通過調(diào)用來執(zhí)行。以下是對存儲過程和觸發(fā)器的簡要說明以及如何創(chuàng)建和使用它們: 存儲過程(Stored Procedure): 定義: 存儲過程是一組SQL語句

    2024年01月21日
    瀏覽(96)
  • MySQL高級篇復盤筆記(一)【存儲引擎、索引、SQL優(yōu)化、視圖、觸發(fā)器、MySQL管理】

    MySQL高級篇復盤筆記(一)【存儲引擎、索引、SQL優(yōu)化、視圖、觸發(fā)器、MySQL管理】

    ? 作者主頁:歡迎來到我的技術(shù)博客?? ? 個人介紹:大家好,本人熱衷于 Java后端開發(fā) ,歡迎來交流學習哦!( ̄▽ ̄)~* ?? 如果文章對您有幫助,記得 關(guān)注 、 點贊 、 收藏 、 評論 ?????? ?? 您的支持將是我創(chuàng)作的動力,讓我們一起加油進步吧?。?!???? 連接層

    2024年02月06日
    瀏覽(111)
  • MySQL---存儲函數(shù)、觸發(fā)器

    MySQL---存儲函數(shù)、觸發(fā)器

    1. 存儲函數(shù) MySQL 存儲函數(shù)(自定義函數(shù)),函數(shù)一般用于計算和返回一個值,可以將經(jīng)常需要使用的計算 或功能寫成一個函數(shù)。 存儲函數(shù)和存儲過程一樣,都是在數(shù)據(jù)庫中定義一些 SQL 語句的集合。 存儲函數(shù)與存儲過程的區(qū)別: 存儲函數(shù)有且只有一個返回值,而存儲過程可

    2024年02月05日
    瀏覽(237)
  • MySQL-SQL存儲過程/觸發(fā)器詳解(上)

    MySQL-SQL存儲過程/觸發(fā)器詳解(上)

    ?? 作者:小劉在C站 ?? 個人主頁: ?小劉主頁? ?? 努力不一定有回報,但一定會有收獲加油!一起努力,共赴美好人生! ?? 學習兩年總結(jié)出的運維經(jīng)驗,以及思科模擬器全套網(wǎng)絡實驗教程。專欄: 云計算技術(shù) ??小劉私信可以隨便問,只要會絕不吝嗇,感謝CSD

    2024年02月09日
    瀏覽(86)
  • MySQL-SQL存儲過程/觸發(fā)器詳解(下)

    MySQL-SQL存儲過程/觸發(fā)器詳解(下)

    ?? 作者:小劉在C站 ?? 個人主頁: ?小劉主頁? ?? 努力不一定有回報,但一定會有收獲加油!一起努力,共赴美好人生! ?? 學習兩年總結(jié)出的運維經(jīng)驗,以及思科模擬器全套網(wǎng)絡實驗教程。專欄: 云計算技術(shù) ??小劉私信可以隨便問,只要會絕不吝嗇,感謝CSD

    2024年02月11日
    瀏覽(92)
  • Mysql數(shù)據(jù)庫實驗報告--實驗五 存儲過程和觸發(fā)器

    Mysql數(shù)據(jù)庫實驗報告--實驗五 存儲過程和觸發(fā)器

    在這個系列會更新一些最近老師要求寫的實驗報告~ 大家盡量對著我的文章做一個參考,不要盲目的cv,畢竟這個對于我們以后的工作學習還是十分重要的。 從這個實驗開始,就不在cmd命令行里面進行mysql數(shù)據(jù)庫的操作,因為代碼長度和代碼的復雜性,需使用 MySQL Workbench: 雙

    2024年02月09日
    瀏覽(101)
  • MySQL-SQL存儲函數(shù)以及觸發(fā)器詳解

    MySQL-SQL存儲函數(shù)以及觸發(fā)器詳解

    ?? 作者:小劉在C站 ?? 個人主頁: ?小劉主頁? ?? 努力不一定有回報,但一定會有收獲加油!一起努力,共赴美好人生! ?? 學習兩年總結(jié)出的運維經(jīng)驗,以及思科模擬器全套網(wǎng)絡實驗教程。專欄: 云計算技術(shù) ??小劉私信可以隨便問,只要會絕不吝嗇,感謝CSD

    2024年02月11日
    瀏覽(95)
  • 存儲過程觸發(fā)器

    存儲過程: 存儲過程是一組預編譯的SQL語句,可以在數(shù)據(jù)庫中存儲并重復使用。存儲過程可以提高性能、減少網(wǎng)絡流量并提高安全性。MSSQL中的存儲過程使用T-SQL編寫。 觸發(fā)器: 觸發(fā)器是一種特殊類型的存儲過程,它會在數(shù)據(jù)庫中執(zhí)行某個操作(如INSERT、UPDATE或DELETE)時自動

    2024年02月06日
    瀏覽(95)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包