1. 程式人生 > >MySQL筆記(二):儲存結構、函式、流程控制

MySQL筆記(二):儲存結構、函式、流程控制

MySQL筆記(二):變數、儲存結構、函式、流程控制

變數

MySQL中 的變數分為系統變數和自定義變數,系統變數分為全域性變數和會話變數,自定義變數分為區域性變數和使用者變數

一、系統變數

作用域:

①全域性變數作用域:伺服器每次啟動將為所有的全域性變數賦初始值,針對於所有的會話(連線)有效,但不能跨重啟,如果想重啟之後依然生效就要手動修改配置檔案

②會話變數作用域:只針對當前會話有效,並且不能跨重啟

使用的語法:

①檢視所有的系統變數

show global|[session] variables;

②檢視滿足條件的系統變數

#檢視字符集
show global|[session] variables like '%char%';

③檢視指定的某個系統變數的值

select @@global|[session].系統變數名;

# 檢視當前會話的事務隔離級別
select @@tx_isolation;

④改變系統變數的值

# 方式一:
set global|[session] 系統變數 = 值;

# 方式二:
set @@global|[session].系統變數名 = 值;

注意:如果變數是全域性級別,則前面需要加上global;如果是會話級別,則加session,也可以不加,預設就是會話級別

二、自定義變數

(1)使用者變數

作用域:針對於當前會話(連線)有效,等同於會話變臉的作用域,可以應用在任何地方(即begin end之內或之位)

應用:

①宣告並初始化,宣告時必須進行初始化,可以使用SET或SELECT關鍵字和 =或:=操作符進行宣告和初始化操作,SELECT 關鍵字必須搭配 := 操作符使用

方式一:SET @使用者變數名 = 值;

方式二:SET @使用者變數名 := 值;

方式一:SELECT @使用者變數名 := 值;

②賦值,更新使用者變數的值

方式一:通過SET或SELETCT關鍵字,使用方式和宣告時一樣

SET @使用者變數名 = 值;

SET @使用者變數名 := 值;

SELECT @使用者變數名 := 值;

方式二:使用SELECT INTO關鍵字,欄位值必須是一個值

SELECT 欄位 INTO @變數名 FROM 表;

③使用,使用之前必須先宣告

檢視使用者變數的值:SELECT @使用者變數名;

# 宣告並初始化使用者變數
SET @count = 0;

# 檢視使用者變數值
SELECT @count;

# 更新使用者變數值
SELECT count(*) INTO @count
FROM employees;

(2)區域性變數

作用域:僅僅在定義它的begin end中有效

應用:

①宣告區域性變數

方式一:只宣告,不賦值

DECLARE 區域性變數名 型別;

方式二:宣告並賦值

DEECLARE 區域性變數名 型別 DEFAULT 值;

②賦值

方式一:通過SET或SELECT,區域性變數名前面不需要加@

SET 區域性變數名 = 值;

SET 區域性變數名 := 值;

SELECT 區域性變數名 := 值;

方式二:通過SELECT INTO,區域性變數名前必須加上@

SELECT 欄位名 INTO @區域性變數名 FROM 表;

③使用

查詢變數名

SELECT 區域性變數名;

(三)使用者變數 PK 區域性變數

作用域 定義和使用的位置 語法
使用者變數 當前會話 當前會話的任何位置 必須加@符號,宣告時不用限定型別
區域性變數 僅僅在定義它的begin end中有效 只能在begin end中,且為第一句話 除SELECT INOT外不需要使用@符號,宣告時需要限定型別

(4)案例:

# 使用者變數
SET @m=1;
SET @n=2;
SET  @sum = @m + @n;
SELECT @sum;
儲存過程和函式

儲存過程和函式類似於JAVA中的方法

一、儲存過程

含義:一組預先編譯好的SQL語句的集合,可以理解成批處理語句

優點:①提高程式碼的重用性

​ ②簡化操作

​ ③減少編譯次數和資料庫的連線次數,提高效率

應用場景:常用於增刪改資料,特別是一次性插入大量資料可以大大提高效率

應用:

①建立語法

CREATE PROCEDURE 儲存過程名(引數列表)

BEGIN

​ 儲存過程體(一組合法的SQL語句)

END

注意事項:

  • 引數列表中包含三部分:引數模式、引數名、引數型別

    IN userId INT
    
  • 引數模式:

    • IN:該引數可以作為輸入,也就是說該引數需要呼叫方在呼叫時傳入值

    • OUT:該引數可以作為輸出,也就是說該引數可以作為返回值

    • INOUT:該引數既可以作為輸入又可以作為輸出,也就是說該引數既需要傳入值也可以返回值

    • 如果儲存過程體中僅僅只有一句話,BEGIN END可以省略

    • 儲存過程體中的每條SQL語句的結尾必須加分號,儲存過程的結尾可以使用DELIMITER重新設定

      語法:DELIMITER 結束標記;

      # 以&作為儲存過程的結尾符
      DELIMITER &;
      

②呼叫語法

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

案例:

  • 注意:儲存過程的命令只能在命令列中執行
# 修改結束標記為 $,後面不要加分號
DELIMITER $

# 案例一:儲存過程的引數列表中沒有引數
# 第一步:建立儲存過程
CREATE PROCEDURE p1()
BEGIN
	INSERT INTO admin(`username`, `password`) VALUES
		('user1', '123456'),
		('user2', '123456'),
		('user3', '123456'),
		('user4', '123456'),
		('user5', '123456'); # sql語句後面必須加上分號,表示該SQL語句的結束
END $

# 第二步:呼叫儲存過程
CALL p1()$

# 案例二:儲存過程的引數列表中有IN模式的引數
CREATE PROCEDURE p2(IN username VARCHAR(20), IN password VARCHAR(20))
BEGIN
	# 宣告區域性變數
	DECLARE count INT DEFAULT 0;
	# 也可以在begin end中宣告使用者變數
	# SET @sum = 0;
	SELECT count(*) INTO count
	FROM admin as a
	WHERE a.username = username # 引數可以直接使用,如果引數和表的欄位名重名,可以在表的欄位名前面加上表面進行限定
	AND a.password = password; 
	
	SELECT IF(count > 0,  '登入成功', '登入失敗');
END $

CALL p2('user2', '123456')$

# 案例三:儲存過程的引數列表中有OUT模式的引數
CREATE PROCEDURE p3(IN userId INT, OUT username VARCHAR(20), OUT password VARCHAR(20))
BEGIN
	# 將a.username的值儲存在username變數中,將a.password儲存在password變數中
	SELECT a.username, a.password INTO username, password
	FROM admin a
	WHERE a.id = userId;
END $

# 儲存過程的實參列表中的使用者變數@username和@password可以不進行宣告,直接使用
CALL p3(1, @username, @password) $
SELECT @username, @password $

# 將結束標記還原成 ; 
DELIMITER ;

③刪除儲存過程

語法:DROP PROCEDURE 儲存過程名;

④檢視儲存過程的資訊

SHOW CREATE PROCEDURE 儲存過程名;

二、函式

函式的含義和優點與儲存過程一樣

函式與儲存過程的區別:儲存過程可以有0個返回或多個返回,而函式有且僅有一個返回;儲存過程適合做資料的批量插入和批量更新操作,而函式適合做處理資料後返回一個結果

①建立函式

語法:

CREATE FUNCTION 函式名(引數列表) RETURNS 返回型別

BEGIN

​ 函式體

END

注意:

  • 函式的引數列表包含兩個部分:引數名和引數型別
  • 函式的函式體中肯定有RETURN語句,如果沒有會報錯;如果RETURN語句不是放在函式體的最後面也不會報錯,但是不建議這麼做
  • 如果函式體中只有一條SQL語句,BEGIN END可以省略
  • 也需要使用DELIMITER語句設定結束標記

②呼叫函式

語法:SELECT 函式名(引數列表);

③檢視函式資訊

語法:SHOW CREATE FUNCTION 函式名;

④刪除函式

語法:DROP FUNCTION 函式名;

案例:

DELIMITER $

# 案例一:無引數
CREATE FUNCTION f1() RETURNS INT
BEGIN
	DECLARE count INT DEFAULT 0;
	SELECT COUNT(*) INTO count FROM admin;
	return count;
END $

SELECT f1() $

# 案例二:有引數
CREATE FUNCTION f2(num1 FLOAT, num2 FLOAT) RETURNS FLOAT
BEGIN
	DECLARE sum FLOAT DEFAULT 0;
	SET sum = num1 + num2;
	RETURN sum;
END $
 
SELECT f2(1.0, 2.5);

DELIMITER ;
流程控制結構

流程控制結構分為:順序結構、分支結構和迴圈結構

一、分支結構

(1)、IF函式

①功能:實現簡單雙分支

②作用域:可以作為表示式放在任何位置,即可以在begin end內和begin end外使用

③語法:

IF (條件表示式, 值1, 值2)

當條件表示式成立時返回值1,否則返回值2

④應用:

select IF(10>5, '10>5成立', '10>5不成立');

(2)、case結構

①功能:實現多分支

②作用域:可以放在任何位置。如果放在begin end 外面,作為表示式結合著其他語句使用;如果放在begin end 裡面,一般作為獨立的語句使用

③語法:

語法1:類似於switch
case 表示式或欄位
​ when 值1 then 語句1;
​ when 值2 then 語句2;
​ …
​ else 語句n;
end;

語法2:
case
​ when 條件1 then 語句1;
​ when 條件2 then 語句2;
​ …
​ else 語句n;
end [case];

④應用:

# 在begin end 外面
SELECT 
	employee_id, last_name, salary,
	CASE salary
		WHEN salary>30000 then 'A級'
		WHEN salary>25000 THEN 'B級'
		WHEN salary>20000 THEN 'C級'
		WHEN salary>15000 THEN 'D級'
		WHEN salary>10000 THEN 'E級'
		ELSE 'F級'
	END as 'level'
FROM
	employees

# 在begin end 裡面
CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
BEGIN 
	DECLARE ch CHAR DEFAULT 'A';
	
	CASE 
      WHEN score>90 THEN SET ch='A';
      WHEN score>80 THEN SET ch='B';
      WHEN score>60 THEN SET ch='C';
      ELSE SET ch='D';
	END CASE;
	
	RETURN ch;
END $

(3)、IF結構

①功能:類似於多重if

②作用域:只能應用在begin end 中

③語法:

if 條件1 then

​ 語句1;
elseif 條件2 then

​ 語句2;

else

​ 語句n;
end if;

④應用:

CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
	DECLARE ch CHAR DEFAULT 'A';
	IF score>90 THEN SET ch='A';
	ELSEIF score>80 THEN SET ch='B';
	ELSEIF score>60 THEN SET ch='C';
	ELSE SET ch='D';
	END IF;
	RETURN ch;
END $
二、迴圈結構

流程控制

分類:iterate、leave

功能:

①iterate類似於 continue,繼續,結束本次迴圈,繼續下一次

② leave 類似於 break,跳出,結束當前所在的迴圈

迴圈結構

(一)while結構

①語法:標籤可以省略,當需要使用到迴圈控制時,前面的標籤才會用到

[標籤:]while 迴圈條件 do

迴圈體;

end while [標籤];

⑥應用:

# 向admin表中新增insertCount條資料
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	WHILE i<=insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');
		SET i=i+1;
	END WHILE;
END $

(二)、loop

①功能:一般用來模擬死迴圈

②語法:

[標籤:] loop

迴圈體;

end loop [標籤];

(三)repeat

①功能:相當於do …while,但是until中的條件是結束迴圈的條件

②語法:

[標籤:] repeat

迴圈體;

until 結束迴圈的條件
end repeat [標籤];

綜合案例

場景:admin表中只有三個欄位,分別是id(自增主鍵)、username、password,要求向admin表中新增指定數量的資料,username欄位和password欄位的值隨機生成,並且長度可以指定

原始碼:

DELIMITER $

DROP FUNCTION IF EXISTS generate_str_random;
/**
*功能:建立一個函式,生成指定長度的隨機字串
*引數:
*type是生成的字串型別,分別為username和password,兩種型別使用的字元庫不同,username型別生成的隨機字  *符串中只有字母,password型別生成的隨機字串中只有數字
*len是生成的隨機字串的長度
**/
CREATE FUNCTION generate_str_random(type VARCHAR(20), len INT) RETURNS VARCHAR(26) 
BEGIN
	# 儲存生成的隨機字串
	DECLARE str VARCHAR(20) DEFAULT '';
	# 生成使用者名稱的字元庫
	DECLARE str1 VARCHAR(54) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	# 生成密碼的字元庫
	DECLARE str2 VARCHAR(10) DEFAULT '0123456789';
	# 記錄迴圈次數
	DECLARE i INT DEFAULT 0;
	# 儲存每次隨機得到的字元
	DECLARE s CHAR DEFAULT '';
	# 儲存隨機生成的數字
	DECLARE num INT DEFAULT 1;

	IF type='username' THEN # 生成使用者名稱的隨機字串
		# 迴圈,每次隨機獲取一個字元,將得到的字元加入帶字串中
		WHILE i<len DO
			# 生成一個隨機數,範圍為1到字元庫的長度,向上取整
			SET num = CEIL(RAND() * LENGTH(str1));
			# 從字元庫的num位置擷取一個字元
			SET s = SUBSTR(str1, num, 1);
			# 將隨機生產的字元拼接到str中
			SET str = CONCAT(str, s);
			SET i = i+1;
		END WHILE;
	ELSEIF type='password' THEN # 生成密碼的隨機字串
		# 迴圈,每次隨機獲取一個字元,將得到的字元加入帶字串中
		WHILE i<len DO
			# 生成一個隨機數,範圍為1到字元庫的長度,向上取整
			SET num = CEIL(RAND() * LENGTH(str2));
			# 從字元庫的num位置擷取一個字元
			SET s = SUBSTR(str2, num, 1);
			# 將隨機生產的字元拼接到str中
			SET str = CONCAT(str, s);
			SET i = i+1;
		END WHILE;
	ELSE
		SET str = '';
	END IF;
	
	return str;
END $

DROP PROCEDURE IF EXISTS insert_admin_user;
/**
*功能:建立一個儲存過程,用於向admin表中新增指定數量的使用者,使用者名稱和密碼隨機生成
*引數:
*num用於指定插入的資料量
**/
CREATE PROCEDURE insert_admin_user(IN num INT)
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE len INT DEFAULT 6;
  # 迴圈向admin表中加入資料
  WHILE i < num DO
  	INSERT INTO admin(`username`, `password`) values(generate_str_random('username', len), generate_str_random('password', len));
    SET i = i+1;
  END WHILE;
END $

# 呼叫儲存過程,向admin表中插入1000條資料
CALL insert_admin_user(1000) $

DELIMITER ;