MySQL 存儲過程、自定義函數、事務、保存點 和 流程控制( if 、case 、loop、leave、iterate 、repeat 和 while )的語法、創建和使用

文章目錄

一、存儲過程

1.1、語法:

1)創建存儲過程

drop procedure if exists [存儲過程名] ;

delimiter [結束標記]
create procedure [存儲過程名]([參數1], [參數2] ...)
begin
    [存儲過程體(一組合法的sql語句)]
end [結束標記]

delimiter ;

參數,其格式爲 [in|out|inout] parameter_name type

  1. in 表示 輸入參數;
  2. out 表示 輸出參數;
  3. inout 表示 此參數既可以輸入也可以輸出;
  4. param_name 表示 參數名稱;
  5. type 表示 參數的類型。

delimiter [結束標記] 本身與存儲過程的語法無關,用於表示存儲過程的結束。
最後一個命令 delimiter ; 將 分隔符 改回 分號

存儲過程體中可以有多條sql語句,如果僅僅一條sql語句,則可以省略 begin end` 。

2)調用存儲過程

call [存儲過程名]([ proc_parameter [,proc_parameter ...]])

call [存儲過程名]

說明:

當無參數時,可以省略括號,不寫;

當有參數時,不可省略括號。

3)存儲過程修改 : 修改存儲過程,就是刪除重建。

4)刪除存儲過程: drop procedure [if exists] sp_name

1.2、示例

drop table if exists `t_user`;
create table `t_user` (
  `id` int not null auto_increment,
  `name` varchar(20) not null,
  primary key (`id`)
) engine=innodb auto_increment=1 default charset=utf8;

1.2.1、無參數的存儲過程

drop procedure if exists myproc1;
delimiter $
create procedure myproc1()
begin
    insert into t_user values(null, 'Jas'),(null, 'Joy');
end $
delimiter ;

調用,並查看結果:
在這裏插入圖片描述

1.2.3、只有一個 in 參數的存儲過程

drop procedure if exists myproc2;

delimiter $
create procedure myproc2(in userId int)
begin
    select name from t_user where id = userId;
end $

delimiter ;

調用,並查看結果:
在這裏插入圖片描述

1.2.3、包含 in 參數和 out 參數的存儲過程

drop procedure if exists myproc3;

delimiter $
create procedure myproc3(in userId int, out username varchar(20))
begin
    select name into username     # 將查詢到的用戶名賦值給 username
    from t_user where id = userId;
end $
delimiter ;

調用,並查看結果:
在這裏插入圖片描述

  1. 創建存儲過程 myproc3,包含一個in參數和一個out參數 ;
  2. 調用時,傳入刪除的id 和 全局變量 @username ;
  3. select @username 輸出結果。

1.2.4、包含 inout 參數的存儲過程

drop procedure if exists myproc4;

delimiter $
create procedure myproc4(inout a int)
begin
    set a = a * 2;
end $

delimiter ;

調用存儲過程,並查詢結果:

在這裏插入圖片描述

1.2.5、附:根據 時間 修改 狀態:

delimiter $$

use `exam9` $$  ## exam9 是數據庫

drop procedure if exists `updateStatus` $$   ## 如果存在,就刪除

create  procedure `updateStatus`()
begin
    update exam set `status`="已結束" where  `status` != "已結束" and  (now() - endtime)>0  ;
    update exam  set `status`="正在答題"  where   `status` != "已結束" and ( now() - starttime)>=0 
    and  (now() - endtime)<=0;
    
    update haulinfo set bigstatus="已結束" where  bigstatus != "已結束" and  (curdate() - bigenddate)>0; 
    update haulinfo set bigstatus="進行中" where (curdate() - bigenddate)<=0 and (curdate() - bigbegindate)>=0;
    
    update exam set bigstatus=(select bigstatus from haulinfo where bigid=exam.bigid);
end $$

delimiter ;

1.3、區別:

1.3.1、存儲過程的優點:

  1. 存儲過程 就是把經常使用的 sql語句 或 業務邏輯封裝起來,預編譯保存在數據庫中,當需要的時候從數據庫中直接調用,省去了編譯的過程;
  2. 提高了運行速度;
  3. 同時降低網絡數據傳輸量( 不用傳一堆sql代碼快,而是傳一個存儲過程名字和幾個參數)。

1.3.2、存儲過程 與 函數 的區別

  1. 一般來說,存儲過程實現的功能要複雜一點,而函數的實現的功能針對性比較強。

  2. 存儲過程可以有返回值也可以沒有返回值,而自定義函數必須要返回值,且返回值有且只有一個。

  3. 存儲過程一般是作爲一個獨立的部分來執行,而函數可以作爲查詢語句的一個部分來調用,因此它可以在查詢語句中位於 from 關鍵字的後面。 SQL 語句中不可用存儲過程,而可以使用函數。

二、自定義函數 udf(user-defined function )

自定義函數 就像是 abs() 、 concat() 內建函數一樣去擴展 mysql 。

所以,udf 是對 mysql 功能的一個擴展。

2.1、自定義函數 udf

1) 創建 udf

drop function if exists [函數名];

delimiter [結束標記]
create function [函數名]([參數1], [參數2] ...) returns [返回值類型]
begin 
    [方法體]
    return [返回值];
end [結束標記]

delimiter ;

參數,其格式爲 param_name type ,如 username varchar(20)

2) 刪除 udf: drop function [函數名]

3)調用 udf : select [函數名](param_value, ...)

2.2、示例

t_user 表中的數據:
在這裏插入圖片描述

2.2.1、 無參數的自定義函數

查詢t_user 中的數據行數,並返回。

drop function if exists myfun1;

delimiter $
create function myfun1() returns int
begin
    declare sum int default 0;    # 定義局部變量 sum,默認值爲 0
    
    select count(*) into sum    # 將查詢的結果賦值給 sum
    from t_user;
    return sum;
end $

delimiter ;

調用結果:
在這裏插入圖片描述

2.2.2、有參數的自定義函數

drop function if exists myfun2;

delimiter $
create function myfun2(userId int) returns varchar(20)
begin
	set @username='';    # 定義系統會話變量
	select name into @username    # 將用戶名賦值給 username
	from t_user
	where id = userId;
	return @username;
end $

delimiter ;

查看結果:
在這裏插入圖片描述

三、複合結構

3.1、語法格式:

delimiter //
create function if exist deleteById(uid smallint unsigned) returns varchar(20) 
begin
    delete from t_order where id = uid;
    return (select count  (id) from son);
end //

delimiter ;

在函數體中,如果包含多條語句, 我們需要把多條語句放到 begin...end 語句塊中。

begin...end 相當於 java 語言中的 { }

public int method(int param){
	int result=0;
	if(param==1){
		......
		result=......
	}else if{param==2}{
		....
		result=......
	}else{
		.......	
		result=......
	}
	return result;
}

3.2、delimiter 修改默認的結束符

delimiter // 表示 將默認的結束符由 ; 改爲 // ,以後的sql語句都要以 // 作爲結尾 。

3.3、 returns 聲明返回值類型

returns varchar(20) 聲明 返回值 是 20位長度的字符串 。

returns int 聲明返回值 int 。

3.4、reurn 定義 返回值

reurn 語句 也包含在begin...end 中。

3.5、declare 定義局部變量

declare  var_name[,varname]...date_type [default value];

簡單來說就是:

declare 變量1[,變量2,... ]變量類型 [default 默認值]

這些變量的作用範圍是在begin…end程序中,而且定義局部變量語句必須在begin…end的第一行定義

示例:

delimiter //
create function addNum(x smallint unsigned, y smallint unsigned) returns smallint
begin
    declare a, b smallint unsigned default 10; ### 定義局部變量
    set  a = x, b = y;
    return a+b;
end //

delimiter ;

上邊的代碼只是把兩個數相加,當然,沒有必要這麼寫,只是說明局部變量的用法,還是要說明下:這些局部變量的作用範圍是在 begin...end 程序中

四、變量

4.1、系統變量

1)全局變量 (global)

作用域:針對於所有會話(連接)有效,但不能跨重啓。重啓後,配置失效。

# 查看所有全局變量
show global variables;

# 查看滿足條件的部分系統變量
show global variables like '%char%';

# 查看指定的系統變量的值
select @@global.autocommit;

# 爲某個系統變量賦值
set @@global.autocommit=0;
set global autocommit=0;

2)會話變量(默認 session )

作用域:針對於當前會話(連接)有效
系統變量,如果不加 globalsession ,則默認就是 session 。

# 查看所有會話變量
show session variables;  ## 等價於 show variables;

# 查看滿足條件的部分會話變量
show session variables like '%char%';

# 查看指定的會話變量的值
select @@autocommit;
select @@session.tx_isolation;

# 爲某個會話變量賦值
set @@session.tx_isolation='read-uncommitted';
set session tx_isolation='read-committed';

4.2、自定義變量

1)用戶變量 (全局的變量)

作用域: 用戶變量 在當前連接(即當前會話)中都有效。

用戶變量的特點:

  • 不需要聲明,直接使用,
  • 前後數據類型可以不一樣。

示例:
同一個用戶變量,前後可以接收不同類型的賦值。

age 是 int
name 是varchar(20)

set @tmpVal = age;   ## 將age的值賦給 @tmpVal
set @tmpVal = name;  ## 將name的值賦給 @tmpVal

聲明並初始化:

set @變量名=;
set @變量名:=;
select @變量名:=;

賦值:

## 方式一:一般用於賦簡單的值
set 變量名=;
set 變量名:=;
select 變量名:=;


## 方式二:一般用於賦表 中的字段值
select 字段名或表達式 into 變量
from;

使用:

select @變量名;

2)局部變量

作用域: 局變變量在 begin end 語句中有效,超過範圍即失效。

聲明:

declare 變量名 類型 【default 值】;
declare name varchar(20) ;
declare num int default 0;

局部變量 必須在 begin end 的第一行 。

賦值:

# 方式一:一般用於賦簡單的值
set 變量名=;
set 變量名:=;
select 變量名:=;


# 方式二:一般用於賦表 中的字段值
select 字段名或表達式 into 變量
from;

使用:

select 變量名

3)用戶變量與 局部變量的區別:

- 作用域 定義位置 語法
用戶變量 當前會話 會話的任何地方 加@符號,不用指定類型
局部變量 定義它的 begin end 中 begin end 的第一句話 一般不用加@ ,需要指定類型

五、事務和回滾點

5.1、事務

set autocommit=0;    ## 1、取消自動提交
start transaction;   ## 2、開啓事務

要執行的操作

commit;     ## 3、提交事務
rollback;   ## 4、回滾事務

5.2、存儲過程和函數使用事務的格式:

begin  
	set autocommit=0;    ## 取消自動提交
	start transaction;   ## 開啓事務
	 
	要執行的操作
	
	commit;   ## 提交事務
end ;

5.3、保存點

在事務中,設置保存點,
當回滾時,能回滾到這個保存點,
但是 保存點 之前的執行不會回滾 。

set autocommit=0;    ## 取消自動提交
start transaction; 
..... ## SQL語句
savepoint aa; ## 設置保存點,aa 是自定義的名稱,保持唯一
..... ## SQL語句
rollback to aa ## 回滾到保存點。 但是保存點前面執行的SQL執行依然有效。

5.4、示例: 快速生成 1000W 測試數據

MySQL 高級–優化 —— 複合索引(多列索引、聯合索引)的定義、區別、創建和理解 中快速生成 1000W 測試數據。

六、流程控制

存儲過程 和 函數 中可以使用 流程控制語句 來 控制SQL 的執行。

mysql中可以使用 if 、case 、loop、leave、iterate 、repeat 和 while 語句 來進行流程控制。

每個流程中可能包含一個單獨語句,或者是使用 begin...end 構造的複合語句,構造可以被嵌套。

1、if 函數

語法:

if(條件,值1,值2)

如果條件成立,則返回 值1,否則返回 值2
特點:可以用在任何位置。

在這裏插入圖片描述

2、if 條件判斷

根據是否滿足條件,將執行不同的語句。

特點:
與 if 函數 的不同,這個if 條件只能用在 begin end 中 !!

1) if 語法:

if  表達式1 then 語句1;
elseif 表達式2 then 語句2;
...
else 語句n;
end if;

參數說明:

特點:
只能用在 begin end 中 !!

注意: mysql還有一個if()函數,不同於這裏描述的 if 語句。

2) if 示例:

if age>20 then 
	set @count1=@count1+1;  
elseif age=20 then 
	set @count2=@count2+1;  
else 
	set @count3=@count3+1;  
end if; 

說明:

根據age與20的大小關係來執行不同的set語句。

如果age值大於20,那麼將count 1的值加1;

如果age值等於20,那麼將count 2的值加1;

其他情況將 count3 的值加 1 。

最後,if 語句都需要使用 end if 來結束。

3、case when 條件判斷

case when 也用來進行條件判斷,其可以實現 比 if 更復雜的條件判斷。

1)case when 語法:
類似於 switch

case 表達式
	when1 then 結果1或語句1  ## 如果是語句,需要加分號
	when2 then 結果2或語句2  ## 如果是語句,需要加分號
	...
	else 結果n或語句n          ## 如果是語句,需要加分號
endcase## 如果是放在begin end中,則結尾處需要加上case,如果放在select後面不需要

說明:
如果是在 begin end 中,則需要在每個 語句後面加 分號,case 結尾處加 case
如果放在 select 後面,則每個語句後面不需要加分號, case 結尾處不需要加 case

在這裏插入圖片描述

2)case when 語法2:

case 
	when 表達式1 then 結果1或語句1   ## 如果是語句,需要加分號 
	when 表達式2 then 結果2或語句2   ## 如果是語句,需要加分號
	...
	else 結果n或語句n   ## 如果是語句,需要加分號
endcase## 如果是放在begin end中,則結尾處需要加上case,如果放在select後面不需要

說明:
語法1 的when 後面是值,
語法2 的when 後面是 表達式,可以進行區間的判斷,
這個兩個語法最大的區別。

示列:
在這裏插入圖片描述

4、loop 循環

loop 可以使某些特定的語句重複執行,實現一個簡單的循環。

但是 loop 本身沒有停止循環的語句,必須使用 leave、iterate 等才能停止循環。

1) loop 語法:

[begin_label:] loop 
	statement_list 
end loop [end_label] 

參數說明:

  1. begin_label 、end_label 分別表示 循環開始 和 結束的標誌,這兩個標誌必須相同,而且都可以省略;

  2. statement_list 表示需要循環執行的語句。

2) loop 示例

add_num: loop  
	set @count=@count+1;  
end loop add_num ; 

說明:

循環執行 count 加1的操作。

因爲沒有跳出循環的語句,這個循環成了一個死循環。

loop 循環都以 end loop 結束。

5、leave 跳出循環(break)

leave 用於跳出循環。

leave 用於 loop、repeat、while ,中斷 並跳出循環。

1) leave 語法:

leave label 

參數說明:

label 表示 循環的標誌。

2)leave 示例:

add_num: loop 
	set @count=@count+1; 
	if @count=100 then 
		leave add_num ; 
end loop add_num ; 

循環執行 count 加1的操作。

當 count 的值等於100時,則leave語句跳出循環。

6、iterate 跳出本次循環(continue)

iterate 也是跳出循環。但是,iterate 語句是跳出本次循環,然後直接進入下一次循環。

iterate 用於 loop、repeat、while 語句跳過本次循環。

1) iterate 語法:

iterate   label

參數說明:

  1. label 表示循環的標誌。

2)iterate 示例:

add_num: loop
    set @count=@count+1;
    if @count=100 then
    	leave add_num ;
    else if mod(@count,3)=0 then
   		iterate add_num;
    select  from employee ;
end loop add_num ;

說明:

循環執行 count 加1的操作。

當 count 值爲100時結束循環。

如果 count 的值能夠整除3,則跳出本次循環,不再執行下面的select語句。

leave 和 iterate 的區別

相同點:

leave 和 iterate 都用來跳出循環語句,但兩者的功能是不一樣的。

不同點:

leave 是跳出整個循環,然後執行循環後面的程序。

iterate 是跳出本次循環,然後進入下一次循環。

7、repeat (先)循環

repeat 是有條件控制的循環。當滿足特定條件時,就會跳出循環語句。

1)repeat 語法:

repeat 
	statement_list 
	until search_condition    # until 後面沒有分號(;),否則 報錯
end repeat;

參數說明:

  1. statement_list 表示 循環的執行語句;

  2. search_condition 表示 結束循環的條件,滿足該條件時循環結束。

2) repeat 示例:

repeat 
	set @count=@count+1; 
	until @count=100 
end repeat ; 

循環執行count 加1的操作。

當 count 值爲10 0時 結束循環。

repeat循環都用end repeat結束。

8、while (先判斷,再)循環

while 也是有條件控制的循環語句。但while 和 repeat 是不一樣的。

while 是當滿足條件時,執行循環內的語句。

1) while 語法:

while   search_condition do 
	statement_list 
end while ;

參數說明:

  1. search_condition 表示 循環執行的條件,滿足該條件時循環執行;

  2. statement_list 表示 循環的執行語句。

2) while 示例:

while   @count<100 do 
	set @count=@count+1; 
end while ; 

循環執行count 加1的操作。

如果 count 值小於100時執行循環;

如果 count 值等於100了,則跳出循環。

while 循環需要使用end while 來結束。

七、 循環示例

1、 loop 循環的示例

delimiter $$

drop procedure if exists `sp_testloop` $$

create  procedure `sp_testloop`(
	in p_number int, #要循環的次數	
	in p_startid int #循環的起始值
)
begin  
    declare v_val int default 0;  
    set v_val=p_startid;

    loop_label:  loop   #循環開始
        set v_val=v_val+1; 
         
        if(v_val>p_number)then
            leave  loop_label;  # 終止循環
        end if;
    end loop; 
    select concat('testloop_',v_val) as tname;
end $$

delimiter ;

call sp_testloop(1000,0);

2、while循環的示例

delimiter $$

drop procedure if exists `sp_test_while`$$

create  procedure `sp_test_while`(
	in p_number int, #要循環的次數
	in p_startid int #循環的起始值
)
begin  
	declare v_val int default 0;  
	set v_val=p_startid;
	outer_label:  begin  #設置一個標記
		while v_val<=p_number do  
			set v_val=v_val+1;  
			if(v_val=100)then
				leave  outer_label;  #滿足條件,終止循環,跳轉到 end outer_label標記
			end if;
		end while;
		
		select '我是while外,outer_label內的SQL';## 這句SQL在outer_label代碼塊內,所以level後,這句SQL將不會執行;
	
	#只要是在outer_label代碼塊內 任意位置 Leave outer_label,那麼Leave後的代碼將不再執行
	end outer_label;
	select concat('test',v_val) as tname;
end$$

delimiter ;

call sp_test_while(1000,0);

3、repeat 循環的示例

delimiter $$
drop procedure if exists `sp_test_repeat`$$

create  procedure `sp_test_repeat`(
	in p_number int, #要循環的次數
	in p_startid int #循環的起始值
)
begin  
	declare v_val int default 0;  
	set v_val=p_startid;

	repeat  #repeat循環開始
	 
		set v_val=v_val+1; 
		until v_val > p_number   #終止循環的條件,注意這裏不能使用';'分號,否則報錯     
		  
	end repeat; #循環結束 
	 
	select concat('test',v_val) as tname;
end$$

delimiter ;

call sp_test_repeat(1000,0);

4、mysql 生成隨機數 —— 數字、字符串、手機號、日期、姓名、一段中文漢字

mysql 生成隨機數 —— 數字、字符串、手機號、日期、姓名、一段中文漢字

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章