自定義函數(shù):
概念:用戶自定義函數(shù)(user-defined function,UDF)是一種對 MySQL 擴展的途徑,其用法與內(nèi)置函數(shù)相同。
創(chuàng)建自定義函數(shù)語法結(jié)構(gòu):
CREATE FUNCTION function_name?
RETURNS?
{ STRING | INTEGER | REAL | DECIMAL}
routine_body
函數(shù)體(routine_body):
⑴ 函數(shù)體由合法的 SQL 語句構(gòu)成
⑵ 函數(shù)體可以是簡單的 SELECT 或 INSERT 語句
⑶ 函數(shù)體如果為復(fù)合結(jié)構(gòu)則使用 BEGIN ... END 語句
⑷ 復(fù)合結(jié)構(gòu)可以包含聲明,循環(huán),控制結(jié)構(gòu)
刪除自定義函數(shù)語法結(jié)構(gòu):
DROP FUNCTION [ IF EXISTS ] function_name
案例:
無參函數(shù):
將系統(tǒng)默認返回的日期格式化為年月月時分表
把這個返回格式封裝成一個自定義函數(shù),返回類型為 VARCHAR,返回的函數(shù)體為 DATE_FORMAT():
帶參函數(shù):
創(chuàng)建一個函數(shù) f2,傳入 num1 和 num2 返回它們的平均值
調(diào)用該函數(shù):
帶有復(fù)合結(jié)構(gòu)函數(shù)體的自定義函數(shù):
首先查看下表 tb_user5 的記錄:
如果每次插入記錄都需要寫 INSERT 語句,會有點麻煩。現(xiàn)在把 INSERT 語句封裝成一個函數(shù),并返回當(dāng)前插入的記錄的 ID:
分號 “;” 和系統(tǒng)默認的結(jié)束符沖突,所以通過 DELIMITER $$ 將分隔符修改為 “$$”。由于有多個語句要執(zhí)行,所以需要用 BEGIN ... END 構(gòu)成一個聚合體。
調(diào)用函數(shù) adduser:
返回該條記錄的 ID,再查詢一下表 tb_user5 的記錄:
定義局部變量:
DECLARE?var_name [,varname] ... date_type [DEFAULT?VALUE]
局部變量的作用范圍是在 BEGIN...END 語句中,而且定義局部變量語句必須在 BEGIN...END語句中的第一行定義
為變量賦值:
SET?parameter_name = value [,parameter_name = value...]
SELECT ... INTO?parameter_name
用戶變量語法(可以理解為全局變量):
SET?@param_name = value
流程控制語句:
⑴ IF 語句
? ? 語法結(jié)構(gòu):
? ??IF search_condition THEN statement_list
????[ELSEIF search_condition THEN statement_list] ...
????[ELSE statement_list]
????END IF
? ? 其中,search_condition 表示條件判斷語句,statement_list 表示執(zhí)行語句。
????案例:
????傳入一個參數(shù),根據(jù)數(shù)值判斷返回指定的數(shù)值。
⑵ CASE 語句
? ? 語法結(jié)構(gòu):
????①
? ??CASE case_value
????WHEN when_value THEN statement_list
????[WHEN when_value THEN statement_list] ...
????[ELSE statement_list]
????END CASE
? ? 其中,case_value 表示條件判斷的變量,when_value 表示變量的取值,
????statement_list 表示執(zhí)行語句
? ? 案例:
? ??②
? ??CASE
????WHEN search_condition THEN statement_list
????[WHEN search_condition THEN statement_list] ...
????[ELSE statement_list]
????END CASE
? ? 其中,search_condition 表示條件判斷,statement_list 表示執(zhí)行語句
? ? 案例:
⑶ LOOP 語句
? ? 概念:
????實現(xiàn)一個簡單的循環(huán),沒有結(jié)束循環(huán)語句,需要通過 LEAVE 來停止循環(huán)
? ? 語法結(jié)構(gòu):
????[begin_label:] LOOP
????statement_list
????END LOOP [end_label]
? ? 其中,begin_label 和 end_label 表示開始和結(jié)束的標志可以隨意命名,
????statement_list 執(zhí)行語句。
⑷ LEAVE 語句
? ? 概念:
????結(jié)束本次循環(huán)
? ? 語法結(jié)構(gòu):
? ??LEAVE label
? ? 案例:
? ? 聲明局部變量 a 循環(huán)累加至 10 打印出來。
⑸?ITERATE 語句
? ? 概念:
????跳出本次循環(huán),重新執(zhí)行循環(huán),只能出現(xiàn)在 LOOP,REPEATE,WHILE 循環(huán)中。
? ? 語法結(jié)構(gòu):
? ??ITERATE label
? ? 案例:
????執(zhí)行結(jié)果:
????由圖,聲明兩個局部變量 x,y,循環(huán) x+1 當(dāng) x>10 時結(jié)束本次循環(huán);當(dāng) x=5 時,y = x*2,
? ? 所以 y = 10 ,接著?ITERATE lp 重新執(zhí)行 LOOP 循環(huán),直到循環(huán)結(jié)束。
⑹?REPEAT 語句
? ? 概念:
????含有條件控制的循環(huán)語句,滿足條件跳出循環(huán)
? ? 語法結(jié)構(gòu):
? ??[begin_label:] REPEAT
????statement_list
????UNTIL search_condition?END REPEAT [end_label]
? ? 案例:
? ? 由圖,聲明局部變量 x 循環(huán)加1,大于10時結(jié)束循環(huán)。
⑺?WHILE 語句
? ? 概念:
????含有條件控制的循環(huán)語句,滿足條件進入循環(huán)
? ? 語法結(jié)構(gòu):
? ??[begin_label:] WHILE search_condition DO
????statement_list
????END WHILE [end_label]
? ? 案例:
? ? 由圖,當(dāng) x < 10 時,循環(huán)加1,x >= 10 時跳出循環(huán)。
存儲過程:
MySQL命令的執(zhí)行流程:
如果把流程里的語法分析和編譯的環(huán)節(jié)省略掉,那么 MySQL 的執(zhí)行效率就會提高。所以這就需要存儲過程來完成。
概念:
存儲過程是 SQL 語句和控制語句的預(yù)編譯集合,以一個名詞存儲并作為一個單元處理,它存儲在數(shù)據(jù)庫里面,可以由應(yīng)用程序調(diào)用執(zhí)行,允許用戶聲明變量和進行流程控制,而且可以接收參數(shù),不僅可以接收輸入類型的參數(shù),也可以接收輸出類型的參數(shù),同時可以存在多個返回值。
存儲過程的效率比單一的 SQL 執(zhí)行效率要高,假設(shè)有兩個 SQL 語句,MySQL 引擎會對這個兩個 SQL 語句進行逐一的語法分析,再編譯,再執(zhí)行,而有了存儲過程后,只有第一次才進行語法分析和編譯流程,后續(xù)調(diào)用只需調(diào)用結(jié)果即可。
優(yōu)點:
⑴ 增強 SQL 語句的功能和靈活性
⑵ 實現(xiàn)較快的執(zhí)行速度
如果某個操作包含大量 SQL 語句,那么這些語句都將被 MySQL 引擎進行逐一的語法分析,編譯和執(zhí)行的過程,所以效率相對較低,而存儲過程是預(yù)編譯的,當(dāng)客戶端第一次調(diào)用存儲過程的時候,MySQL 引擎將對它語法分析和編譯等操作,然后把編譯的結(jié)果存儲到內(nèi)存中,后續(xù)調(diào)用直接從內(nèi)存里面調(diào)用結(jié)果。所以效率大量提高。
⑶ 減少網(wǎng)絡(luò)流量
語法結(jié)構(gòu):
CREATE
[ DEFINER = { user | CURRENT_USER } ]
PROCEDURE sp_name ( [ proc_parameter [,...] ] )
[ characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name_type
其中,
IN 表示該參數(shù)的值必須在調(diào)用存儲過程時指定
OUT 表示該參數(shù)的值可以被存儲過程改變,并且可以返回
INOUT 表示該參數(shù)的調(diào)用時指定,并且可以被改變和返回
修改存儲過程:
注:只能修改簡單的特性,不能修改過程體,若要修改,只能先把存儲過程刪了,重新創(chuàng)建
語法結(jié)構(gòu):
ALTER PROCEDURE sp_name [characteristic ...]
COMMENT 'string'
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
COMMENT:注釋
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í)行
過程體:
⑴ 過程體由合法的 SQL 語句構(gòu)成
⑵ 過程體可以是任意的(增、刪、改、查、多表連接)SQL 語句
⑶ 過程體如果為復(fù)合結(jié)構(gòu)則使用 BEGIN ... END 語句
⑷ 復(fù)合結(jié)構(gòu)可以包含聲明,循環(huán),控制結(jié)構(gòu)
調(diào)用存儲過程:
⑴ CALL sp_name ([ parameter [,...]])
⑵ CALL sp_name [()]
刪除存儲過程:
DROP PROCEDURE [IF EXISTS] sp_name
案例:
創(chuàng)建不帶參數(shù)的存儲過程:
存儲體 sp1() 不帶參數(shù),過程體獲取當(dāng)前版本號,調(diào)用該存儲體:
創(chuàng)建帶有 IN 類型參數(shù)的存儲過程:
查詢下表 tb_goods_cate 的記錄:
再創(chuàng)建一個根據(jù) cate_id 刪除記錄的存儲過程:
注:參數(shù)的變量名不能和表里的字段名一樣
調(diào)用:
刪除 cate_id = 2 的記錄,再查詢下記錄:
cate_id = 2 已刪除。
創(chuàng)建帶有 IN 和 OUT 類型參數(shù)的存儲類型:
由圖,創(chuàng)建存儲過程 test,傳入類目 id,然后查詢對應(yīng)的類目名稱。調(diào)用的時候,傳入 id 等于1,并把返回的名稱賦給全局變量 @name,再通過 SELECT 查詢該變量的值。
創(chuàng)建帶有多個 OUT 類型參數(shù)的存儲類型:
由圖,創(chuàng)建一個存儲過程 test,傳入類型 id,輸出類型該類型的名稱和表里的記錄總數(shù)。
總結(jié):
⑴ 存儲過程實現(xiàn)的功能比較復(fù)雜,而函數(shù)針對性更強,一般情況下,存儲過程主要針對表做操作
⑵ 存儲過程可以返回多個值,而函數(shù)只能有一個返回值
⑶ 存儲過程一般獨立的來執(zhí)行,而函數(shù)可以作為 SQL 語句中的組成部分
以上為本人的一些學(xué)習(xí)筆記,如有出錯歡迎指正,陸續(xù)更新!!!