1. 程式人生 > 其它 >Mysql基礎:06.檢視、變數、儲存過程、函式、流程控制

Mysql基礎:06.檢視、變數、儲存過程、函式、流程控制

一、檢視

檢視:虛擬表,和普通表一樣使用。mysql 5.1版本出現的新特性,是通過表動態生成的資料

檢視應用場景:

  • 多個地方用到同樣的查詢結果
  • 該查詢結果使用的sql語句較複雜

(有點函式的味道)

檢視的優點:

  • 重用sql語句
  • 簡化複雜的sql操作,不必知道它的查詢細節
  • 保護資料,提高安全性

1. 檢視的建立

語法:create view 檢視名 as 查詢語句

案例:

USE myemployees;
#1.查詢姓名中包含a字元的員工名、部門名和工種資訊
#①建立檢視
CREATE VIEW myv1 AS
SELECT `last_name`,`department_name`,`job_title`
FROM `employees` e
JOIN `departments` d ON e.`department_id` = d.`department_id`
JOIN `jobs` j ON e.`job_id` = j.`job_id`;
#②使用檢視
SELECT * FROM myv1 WHERE `last_name` LIKE '%a%';

#2.查詢各部門的平均工資級別
#①建立檢視檢視每個部門的平均工資
CREATE VIEW myv2 AS
SELECT AVG(`salary`) ag, `department_id`
FROM `employees` GROUP BY `department_id` 
#②使用檢視
SELECT myv2.ag,g.`grade_level`
FROM myv2 JOIN `job_grades` g 
ON myv2.ag BETWEEN g.`lowest_sal` AND g.`highest_sal`;

#3.查詢平均工資最低的部門資訊
#使用建立好的檢視2
SELECT * FROM myv2 ORDER BY ag LIMIT 1;

#4.查詢平均工資最低的部門名和平均工資
#①建立檢視檢視平均工資最低的部門資訊
CREATE VIEW myv3 AS
SELECT * FROM myv2 ORDER BY ag LIMIT 1; # 套娃
#②使用檢視3
SELECT d.`department_name`,m.ag
FROM myv3 m JOIN `departments` d
ON m.`department_id` = d.`department_id`;

2. 檢視的修改

語法:

#方式一:
create or replace view 檢視名 as 查詢語句;
#方式二:
alter view 檢視名 as 查詢語句;

3. 檢視的刪除

使用者可以一次刪除一個或者多個檢視,前提是必須有該檢視的drop許可權

語法:

drop view 檢視1,檢視2,…;

4. 檢視的檢視

語法:

desc 檢視名;
show create view 檢視名;

5. 檢視的更新

檢視是一個虛擬表,可以對其結果進行更新(增刪改)的操作,但一般只用來查詢

更新操作:插入:insert 修改:update 刪除:delete

值得注意的是:對檢視的增刪改操作都會改變檢視from的原表

CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email
FROM employees;

SELECT * FROM myv1;
SELECT * FROM employees;

#1.插入
INSERT INTO myv1 VALUES('張飛','[email protected]');

#2.修改
UPDATE myv1 SET last_name = '張無忌' WHERE last_name='張飛';

#3.刪除
DELETE FROM myv1 WHERE last_name = '張無忌';

檢視一般是用於查詢的,而不是更新的,因為有很多情況是不能更新的,這些情況覆蓋了大部分語句,

  • 包含以下關鍵字的sql語句:分組函式、distinct、group by、having、union或者union all
  • 常量檢視
  • Select中包含子查詢
  • join
  • from一個不能更新的檢視
  • where子句的子查詢引用了from子句中的表

6. 檢視vs表

關鍵字 是否佔用物理空間 使用場景
檢視 view 佔用較小,只儲存sql邏輯 一般用於查詢
table 儲存實際的資料 增刪改查

二、變數

1. 系統變數

系統變數由系統定義,不是使用者定義,屬於伺服器層面,系統變數分為全域性變數會話變數

全域性變數:需要新增global關鍵字,作用域針對於所有會話(連線)有效,但不能跨重啟

會話變數:需要新增session關鍵字,作用域針對於當前會話(連線)有效,如果不寫,預設會話級別。

系統變數使用語法

  • 檢視所有系統變數

    show global|【session】 variables;
    
  • 檢視滿足條件的部分系統變數

    show global|【session】 variables like '%char%';
    
  • 檢視指定的系統變數的值(只能用點式結構)

    select @@global.|【session.】系統變數名;
    
  • 為某個系統變數賦值(兩種方式,方便記憶的話可以統一記點式結構)

    #方式一:
    set @@global|【session】.系統變數名=值;
    #方式二:
    set global|【session】系統變數名=值;
    

案例:

#全域性變數演示:
#①檢視所有全域性變數
SHOW GLOBAL VARIABLES;
#②檢視滿足條件的部分系統變數
SHOW GLOBAL VARIABLES LIKE '%char%';
#③檢視指定的系統變數的值
SELECT @@global.autocommit;
#④為某個系統變數賦值
SET @@global.autocommit = 0;
SET GLOBAL autocommit = 0;


#會話變數演示:
#①檢視所有會話變數
SHOW VARIABLES;
#②檢視滿足條件的部分會話變數
SHOW VARIABLES LIKE '%char%';
#③檢視指定的會話變數的值
SELECT @@autocommit;
SELECT @@session.autocommit;
#④為某個會話變數賦值
SET @@autocommit = 0;
SET @@session.autocommit = 1;
SET SESSION autocommit = 0;

2. 自定義變數

自定義變數分為使用者變數區域性變數

2.1 使用者變數

使用者變數由使用者自定義,而不是系統提供的,作用域:針對於當前會話(連線)有效,作用域同於會話變數,即可以應用在當前會話的任何地方,begin end裡面和外面都可以

語法:

#賦值操作符:=或:=
#①宣告並初始化,不用指定資料型別,會根據初始化的值自動分配資料型別,必須要初始化,只宣告不行!!!
SET @變數名=值;
SET @變數名:=值;
SELECT @變數名:=值;  #select賦值一般不用,要用的話必須只能搭配:=符號!!!

#②賦值(更新變數的值)
#方式一:
SET @變數名=值;
SET @變數名:=值;
SELECT @變數名:=值;
#方式二:利用select語句將表的資訊賦給某個值
SELECT 欄位1,欄位2,… INTO @變數名1,@變數名2,…
FROM 表;

#③使用(檢視、比較、運算等)
SELECT @變數名;

注意點:要搭配@符號使用、使用者變數必須宣告時初始化

例項:

#宣告並初始化
SET @name = 'john';
SET @num := 100;
SELECT @count := 1;

#賦值(更新值)
#將major表的統計資訊賦給count
SELECT COUNT(*) INTO @count
FROM major;

#使用
SELECT @name;
SELECT @num;
SELECT @count;

2.2 區域性變數

區域性變數的作用域僅在定義它的begin end塊中有效,應用在 begin end中的第一句話。它與使用者變數不同,宣告時需要指定資料型別,不用加@符號

語法:

#①宣告,不支援select宣告方式
DECLARE 變數名 型別;
DECLARE 變數名 型別 【DEFAULT 值】;

#②賦值(更新變數的值)
#方式一:
SET 區域性變數名=值;
SET 區域性變數名:=值;
SELECT 區域性變數名:=值;
#方式二:
SELECT 欄位1,欄位2,… INTO 區域性變數名1,區域性變數名2,…
FROM 表;
	
#③使用(檢視變數的值)
SELECT 區域性變數名;

例項:

#區域性變數宣告
DECLARE name1 VARCHAR;
DECLARE num INT DEFAULT 1;
DECLARE count1 INT;

#賦值(更新變數值)
SET name1 = 'tom';
SET num := 2;
SELECT COUNT(*) INTO count1
FROM major;

#使用
SELECT name1;
SELECT num;
SELECT count1;

2.3 使用者變數和區域性變數的對比

作用域 定義位置 語法
使用者變數 當前會話 會話的任何地方 加@符號,不用指定型別
區域性變數 定義它的BEGIN END中 BEGIN END的第一句話 一般不用加@,需要指定型別
#案例:宣告兩個變數,求和並列印
#使用者變數
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;

#區域性變數
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;

三、儲存過程

類似於Java中的方法,將一組完成特定功能的邏輯語句包裝起來,對外暴露名字,理解成批處理語句

好處

  • 1、提高程式碼的重用性
  • 2、簡化操作
  • 3、減少了編譯次數並且減少了和資料庫伺服器的連線次數,提高了效率

1. 儲存過程的建立

1.1 建立語法

CREATE PROCEDURE 儲存過程名(引數模式 引數名 引數型別)
BEGIN
	儲存過程體(一組合法的SQL語句)
END

如果儲存過程體僅僅只有一句話,begin end可以省略,儲存過程體中的每條sql語句的結尾要求必須加分號。

1.2 引數模式

  • in:該引數可以作為輸入,也就是該引數被呼叫時需要傳入值
  • out:該引數可以作為輸出,也就是該引數可以作為返回值 (儲存過程沒有return,在呼叫時宣告變數接收即可)
  • inout:該引數既可以作為輸入又可以作為輸出,也就是該引數既需要傳入值,又可以返回值

1.3 結束標記

MySQL預設的結束標記是分號; 但有時候並不想讓直譯器碰到分號就結束,此時可以使用關鍵字delimiter 指定結束標記,讓直譯器碰到指定標記時才開始執行所有語句

語法:delimiter 結束標記

例項:delimiter $,即告訴直譯器碰到$才執行語句

注意:不要加分號,否則會認為碰到$;才執行

2. 儲存過程的呼叫

呼叫語法:

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

舉例:

#呼叫in模式的引數
CALL p1('值')

#呼叫out模式的引數
SET @name;
CALL p2(@name);
SELECT @name;

#呼叫inout模式的引數
SET @name = 值;
CALL p3(@name);
SELECT @name;

建立和呼叫過程例項:需要在命令提示符中使用

#設定結束標記
DELIMITER $

#1.空參列表:向major表中插入五條記錄
#切換資料庫
USE students
#建立儲存過程
CREATE PROCEDURE myp1()
BEGIN 
	INSERT INTO major VALUES(1,'java'),(2,'c++'),(3,'python'),(4,'golang'),(5,'sql');	
END $
#呼叫儲存過程
CALL myp1()$


#2.建立帶in模式引數的儲存過程:根據員工名,查詢對應的部門名資訊
#切換資料庫
USE myemployees
#建立儲存過程
CREATE PROCEDURE myp2(IN e_name VARCHAR(20))
BEGIN
	SELECT e.`last_name`,d.`department_name`
	FROM `employees` e
	LEFT JOIN `departments` d ON e.`department_id`=d.`department_id`
	WHERE e.`last_name` = e_name;#e_name屬於區域性變數,可以在當前作用域直接使用
END$
#呼叫儲存過程
CALL myp2('K_ing')$


#3.建立帶多個in模式引數的儲存過程:判斷輸入的部門名和位置ID是否匹配
#建立儲存過程
CREATE PROCEDURE myp3(IN d_name VARCHAR(20),IN locat_id INT)
BEGIN
	DECLARE result INT DEFAULT 0;#建立一個變數用於存放判定的結果,建立使用者變數來存放也可以
	
	SELECT COUNT(*) INTO result
	FROM `departments` d
	WHERE d.`department_name` = d_name
	AND d.`location_id` = locat_id;
	
	SELECT IF(result>0,'成功','失敗');
END$
#呼叫儲存過程
CALL myp3('Adm','1700')$ #成功
CALL myp3('Adm','1800')$ #失敗


#4.建立out模式引數的儲存過程:根據輸入的員工名,返回對應的部門名和location_id
#建立儲存過程
CREATE PROCEDURE myp4(IN e_name VARCHAR(20),OUT d_name VARCHAR(20),OUT locat_id INT)
BEGIN
	SELECT d.`department_name`,d.`location_id` INTO d_name,locat_id
	FROM `employees` e
	LEFT JOIN `departments` d
	ON e.`department_id`=d.`department_id`
	WHERE e.`last_name` = e_name;
END$
#呼叫儲存過程
SET @d_name='';#定義使用者變數,這行可省略
SET @locat_id=0;#定義使用者變數,這行可省略
CALL myp4('Abel',@d_name,@locat_id);#呼叫儲存過程
SELECT @d_name,@locat_id$#檢視結果:Sal,2500


留一個問題,呼叫下面這個時,返回的是兩條結果,該用什麼變數接收呢
CALL myp4('K_ing',@d_name,@locat_id);


#5.建立帶inout模式引數的儲存過程:傳入a和b兩個值,最終a和b都翻倍並返回
CREATE PROCEDURE myp5(INOUT a INT,INOUT b INT)
BEGIN
	SET a=a*2;
	SET b=b*2; 
END$

#呼叫儲存過程
SET @m=10;
SET @n=20;
CALL myp5(@m,@n);
SELECT @m,@n$ #20,40

3. 儲存過程的檢視

語法:

show create procedure 儲存過程名;

不能使用desc

4. 儲存過程的刪除

語法:

drop procedure 儲存過程名;

每次只能刪除一個,如DROP PROCEDURE p1;是可以的,DROP PROCEDURE p2,p3;不可以

儲存過程沒有修改,想要改就先刪除再新增新的

四、函式

一組預先編譯好的SQL語句的集合,理解成批處理語句。有且僅有一個返回

1. 與儲存過程的區別

  • 儲存過程:可以有0個返回,也可以有多個返回,適合做批量插入、批量更新
  • 函式:有且僅有1 個返回,適合做處理資料後返回一個結果

2. 函式的建立

MySQL有個引數SET GLOBAL log_bin_trust_function_creators=TRUE ,如果設定為0(預設值),使用者不得建立或修改儲存函式,除非它們具有除CREATE ROUTINE或ALTER ROUTINE特權之外的SUPER許可權。 設定為0還強制使用DETERMINISTIC特性或READS SQL DATA或NO SQL特性宣告函式的限制。 如果變數設定為1,MySQL不會對建立儲存函式實施這些限制。

因此在建立函式時需要將這個引數設定為1

SET GLOBAL log_bin_trust_function_creators=TRUE;

語法:

CREATE FUNCTION 函式名(引數名 引數型別) RETURNS 返回型別
BEGIN
	函式體
END

注意點:

  • 注意關鍵字 function 和 returns
  • 函式體中需要加上return語句return 值,雖然不加不報錯,但沒有意義
  • 函式體中僅有一句話,則可以省略begin end
  • 使用 delimiter語句設定結束標記

3. 函式的呼叫

語法:

SELECT 函式名(引數列表);

案例:

SET GLOBAL log_bin_trust_function_creators=TRUE;
#1.無參有返回:返回公司的員工個數
CREATE FUNCTION myf1() RETURNS INT
BEGIN
	DECLARE c INT DEFAULT 0; #定義區域性變數
	SELECT COUNT(*) INTO c
	FROM employees;
	RETURN c;
END$

SELECT myf1()$


#2.有參有返回:根據員工名,返回它的工資
CREATE FUNCTION myf2(e_name VARCHAR(20)) RETURNS DOUBLE
BEGIN
	SET @sal=0; #定義使用者變數
	SELECT e.`salary` INTO @sal
	FROM `employees` e
	WHERE e.`last_name` = e_name;
	RETURN @sal;
END$

SELECT myf2('Abel')$

返回值定義為區域性變數和使用者變數都可以,區域性變數更常用

4. 函式的檢視

語法:

show create function 函式名;

5. 函式的刪除

語法:

drop function 函式名;

五、流程控制

  • 順序結構:程式從上往下依次執行
  • 分支結構:程式按條件進行選擇執行,從兩條或多條路徑中選擇一條執行
  • 迴圈結構:程式滿足一定條件下,重複執行一組語句

1. 分支結構

1.1 if函式

用於判斷簡單的情況

語法:

if(表示式1,表示式2,表示式3)

判斷表示式1,為真執行表示式2,為假執行表示式3,類似三元表示式

SELECT IF(10<5,'大','小');

SELECT last_name,commission_pct,IF(`commission_pct` IS NULL,'沒獎金','有獎金')AS 備註 FROM employees;

1.2 if結構

用於判斷複雜的情況

語法:

if 條件1 then 語句1;
elseif 條件2 then 語句2;
....
else 語句n;
end if;

此結構只能用在begin end 中

CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
	IF score >90 THEN RETURN 'A';
	ELSEIF score>= 80 THEN RETURN 'B';
	ELSEIF score >= 60 THEN RETURN 'C';
	ELSE RETURN 'D';
	END IF;
END$

SELECT test_if(86)$

1.3 case結構

case結構有兩種用法:

  • 第一種類似於Java中switch case的效果
  • 第二種類似於多重if的效果

case結構可以放在任何地方,

  • 如果放在begin end 外面,作為表示式結合著其他語句使用;(下面第一個案例可以體現)

  • 如果放在begin end 裡面,一般作為獨立的語句使用

1.3.1 when後面加常量

語法:

case 變數或表示式
when 常量1 then 要顯示的值1或語句1
when 常量2 then 要顯示的值2或語句2
...
else 要顯示的值n或語句n
end
/*
案例:查詢員工的工資,要求:
部門號=30,顯示的工資為1.1倍
部門號=40,顯示的工資為1.2倍
部門號=50,顯示的工資為1.3倍
其他部門,顯示的工資為原工資,按department_id升序
*/
SELECT `salary` 原始工資,`department_id`,  # 這一行最後的逗號容易漏,因為case結構放在begin end之外,作為單獨表示式,需要加逗號隔開
CASE `department_id`
WHEN 30 THEN `salary`*1.1
WHEN 40 THEN `salary`*1.2
WHEN 50 THEN `salary`*1.3
ELSE `salary`
END AS 新工資
FROM employees
ORDER BY `department_id` ASC;

1.3.2 when後面加條件

語法:

case 
when 條件1 then 要顯示的值1或語句1
when 條件2 then 要顯示的值2或語句2
...
else 要顯示的值n或語句n
end

和上一個用法相比就是少了case後面的語句,when後面由常量換為條件

#案例 
#建立儲存過程,根據傳入的成績,來顯示等級,比如傳入的成績:90-100, 顯示A,80-90,顯示B,60-80,顯示c,否則,顯示D

CREATE PROCEDURE test_case (IN score INT) 
BEGIN 
	CASE 
	WHEN score>=90 AND score<=100 THEN SELECT 'A'; 
	WHEN score>=80 THEN SELECT 'B';
	WHEN score>=60 THEN SELECT 'C'; 
	ELSE SELECT 'D';
	END CASE; 
END $

CALL test_case(95)$

2. 迴圈結構

位置:只能放在begin end中

三種迴圈都可以省略名稱,但如果迴圈中添加了迴圈控制語句(leave或iterate)則必須新增名稱

2.1 while

類似於Java中的while

語法:

【名稱:】while 迴圈條件 do
		迴圈體
end while 【名稱】;

2.2 repeat

類似於Java中的do-while

語法:

【名稱:】repeat
		迴圈體
until 結束條件 
end repeat 【名稱】;

2.3 loop

死迴圈

語法:

【名稱:】loop
		迴圈體
end loop 【名稱】;

2.4 leave/iterate

  • leave:類似於break,用於跳出所在的迴圈
  • iterate:類似於continue,用於結束本次迴圈,繼續下一次
#1.沒有新增迴圈控制語句
#案例:批量插入,根據次數插入到major表中多條記錄
USE students;

CREATE PROCEDURE while_test(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	WHILE i<=insertCount DO
		INSERT INTO major VALUES(i,'mysql');
		SET i = i+1;
	END WHILE;
END$

CALL while_test(100)$


#2.新增leave語句
#案例:批量插入,根據次數插入到major表中多條記錄,如果次數>20則停止
TRUNCATE TABLE major$

CREATE PROCEDURE while_test1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	a:WHILE i<=insertCount DO
		INSERT INTO major VALUES(i,'mysql');
		IF i>=20 THEN LEAVE a;
		END IF;
		SET i = i+1;
	END WHILE a;
END$

CALL while_test1(100)$


#3.新增iterate語句
#案例:批量插入,根據次數插入到major表中多條記錄,只插入偶數次
TRUNCATE TABLE major$

CREATE PROCEDURE while_test2(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	a:WHILE i<=insertCount DO
		SET i = i+1;
		IF MOD(i,2)!=0 THEN ITERATE a;
		END IF;
		INSERT INTO major VALUES(i,'mysql');
	END WHILE a;
END$

CALL while_test2(100)$