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)$