流程控制介紹
解決復雜問題不可能通過一個SQL語句完成,我們需要執(zhí)行多個SQL操作。流程控制語句的作用就是控制存儲過程中SQL語句的執(zhí)行順序,是我們完成復雜操作必不可少的一部分。只要是執(zhí)行的程序,流程就分為三大類: 順序結(jié)構(gòu):程序從上往下依次執(zhí)行 分支結(jié)構(gòu):程序按條件進行選擇執(zhí)行,從兩條或多條路徑中選擇一條執(zhí)行 循環(huán)結(jié)構(gòu):程序滿足一定條件下,重復執(zhí)行一組語句針對于MySQL的流程控制語句主要有3類。注意:只能用于存儲程序。 條件判斷語句:IF語句和CASE語句 循環(huán)語句:LOOP、WHILE和REPEAT語句 跳轉(zhuǎn)語句:ITERATE和LEAVE語句
分支結(jié)構(gòu)之IF
IF語句的語法結(jié)構(gòu)是:
IF 表達式1 THEN 操作1
表達式2 THEN 操作2]……
操作N]
END IF
根據(jù)表達式的結(jié)果為TRUE或FALSE執(zhí)行相應的語句。這里“[]”中的內(nèi)容是可選的。
end中
舉例1:
DELIMITER //
CREATE PROCEDURE test_if()
BEGIN
#情況1:
#聲明局部變量
#declare stu_name varchar(15);
#if stu_name is null
# then select 'stu_name is null';
#end if;
#情況2:二選一
#declare email varchar(25) default 'aaa';
#if email is null
# then select 'email is null';
#else
# select 'email is not null';
#end if;
#情況3:多選一
DECLARE age INT DEFAULT 20;
IF age > 40
THEN SELECT '中老年';
ELSEIF age > 18
THEN SELECT '青壯年';
ELSEIF age > 8
THEN SELECT '青少年';
ELSE
SELECT '嬰幼兒';
END IF;
END //
DELIMITER ;
舉例2:聲明存儲過程“update_salary_by_eid1”,定義IN參數(shù)emp_id,輸入員工編號。判斷該員工薪資如果低于8000元并且入職時間超過5年,就漲薪500元;否則就不變。
DELIMITER //
CREATE PROCEDURE update_salary_by_eid1(IN emp_id INT)
BEGIN
#聲明局部變量
DECLARE emp_sal DOUBLE; #記錄員工的工資
DECLARE hire_year DOUBLE; #記錄員工入職公司的年頭
#賦值
SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
SELECT DATEDIFF(CURDATE(),hire_date)/365 INTO hire_year FROM employees WHERE employee_id = emp_id;
#判斷
IF emp_sal < 8000 AND hire_year >= 5
THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
END IF;
END //
DELIMITER ;
#調(diào)用存儲過程
CALL update_salary_by_eid1(104);
SELECT DATEDIFF(CURDATE(),hire_date)/365, employee_id,salary
FROM employees
WHERE salary < 8000 AND DATEDIFF(CURDATE(),hire_date)/365 >= 5;
DROP PROCEDURE update_salary_by_eid1;
舉例3:聲明存儲過程“update_salary_by_eid2”,定義IN參數(shù)emp_id,輸入員工編號。判斷該員工薪資如果低于9000元并且入職時間超過5年,就漲薪500元;否則就漲薪100元。
DELIMITER //
CREATE PROCEDURE update_salary_by_eid2(IN emp_id INT)
BEGIN
#聲明局部變量
DECLARE emp_sal DOUBLE; #記錄員工的工資
DECLARE hire_year DOUBLE; #記錄員工入職公司的年頭
#賦值
SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
SELECT DATEDIFF(CURDATE(),hire_date)/365 INTO hire_year FROM employees WHERE employee_id = emp_id;
#判斷
IF emp_sal < 9000 AND hire_year >= 5
THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
ELSE
UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
END IF;
END //
DELIMITER ;
#調(diào)用
CALL update_salary_by_eid2(103);
CALL update_salary_by_eid2(104);
SELECT * FROM employees WHERE employee_id IN (103,104);
#舉例4:聲明存儲過程“update_salary_by_eid3”,定義IN參數(shù)emp_id,輸入員工編號。
#判斷該員工薪資如果低于9000元,就更新薪資為9000元;薪資如果大于等于9000元且
#低于10000的,但是獎金比例為NULL的,就更新獎金比例為0.01;其他的漲薪100元。
DELIMITER //
CREATE PROCEDURE update_salary_by_eid3(IN emp_id INT)
BEGIN
#聲明變量
DECLARE emp_sal DOUBLE; #記錄員工工資
DECLARE bonus DOUBLE; #記錄員工的獎金率
#賦值
SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
SELECT commission_pct INTO bonus FROM employees WHERE employee_id = emp_id;
#判斷
IF emp_sal < 9000
THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id;
ELSEIF emp_sal < 10000 AND bonus IS NULL
THEN UPDATE employees SET commission_pct = 0.01 WHERE employee_id = emp_id;
ELSE
UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
END IF;
END //
DELIMITER ;
分支結(jié)構(gòu)之CASE
CASE語句的語法結(jié)構(gòu)1:
#情況一:類似于switch
CASE表達式
WHEN 值1 THEN 結(jié)果1或語句1(如果是語句,需要加分號)
WHEN 值2 THEN 結(jié)果2或語句2(如果是語句,需要加分號)
...
ELSE 結(jié)果n或語句n(如果是語句,需要加分號)
END [case](如果是放在beginend中需要加上case,如果放在select后面不需要)
CASE語句的語法結(jié)構(gòu)2:
#情況二:類似于多重if
CASE
WHEN 條件1 THEN 結(jié)果1或語句1(如果是語句,需要加分號)
WHEN 條件2 THEN 結(jié)果2或語句2(如果是語句,需要加分號)
...
ELSE 結(jié)果n或語句n(如果是語句,需要加分號)
END [case](如果是放在beginend中需要加上case,如果放在select后面不需要)
#舉例1:基本使用
DELIMITER //
CREATE PROCEDURE test_case()
BEGIN
#演示1:case ... when ...then ...
/*
declare var int default 2;
case var
when 1 then select 'var = 1';
when 2 then select 'var = 2';
when 3 then select 'var = 3';
else select 'other value';
end case;
*/
#演示2:case when ... then ....
DECLARE var1 INT DEFAULT 10;
CASE
WHEN var1 >= 100 THEN SELECT '三位數(shù)';
WHEN var1 >= 10 THEN SELECT '兩位數(shù)';
ELSE SELECT '個數(shù)位';
END CASE;
END //
DELIMITER ;
#舉例2:聲明存儲過程“update_salary_by_eid4”,定義IN參數(shù)emp_id,輸入員工編號。
#判斷該員工薪資如果低于9000元,就更新薪資為9000元;薪資大于等于9000元且低于10000的,
#但是獎金比例為NULL的,就更新獎金比例為0.01;其他的漲薪100元。
DELIMITER //
CREATE PROCEDURE update_salary_by_eid4(IN emp_id INT)
BEGIN
#局部變量的聲明
DECLARE emp_sal DOUBLE; #記錄員工的工資
DECLARE bonus DOUBLE; #記錄員工的獎金率
#局部變量的賦值
SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
SELECT commission_pct INTO bonus FROM employees WHERE employee_id = emp_id;
CASE
WHEN emp_sal < 9000 THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id;
WHEN emp_sal < 10000 AND bonus IS NULL THEN UPDATE employees SET commission_pct = 0.01
WHERE employee_id = emp_id;
ELSE UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
END CASE;
END //
DELIMITER ;
#舉例3:聲明存儲過程update_salary_by_eid5,定義IN參數(shù)emp_id,輸入員工編號。
#判斷該員工的入職年限,如果是0年,薪資漲50;如果是1年,薪資漲100;
#如果是2年,薪資漲200;如果是3年,薪資漲300;如果是4年,薪資漲400;其他的漲薪500。
DELIMITER //
CREATE PROCEDURE update_salary_by_eid5(IN emp_id INT)
BEGIN
#聲明局部變量
DECLARE hire_year INT; #記錄員工入職公司的總時間(單位:年)
#賦值
SELECT ROUND(DATEDIFF(CURDATE(),hire_date) / 365) INTO hire_year
FROM employees WHERE employee_id = emp_id;
#判斷
CASE hire_year
WHEN 0 THEN UPDATE employees SET salary = salary + 50 WHERE employee_id = emp_id;
WHEN 1 THEN UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
WHEN 2 THEN UPDATE employees SET salary = salary + 200 WHERE employee_id = emp_id;
WHEN 3 THEN UPDATE employees SET salary = salary + 300 WHERE employee_id = emp_id;
WHEN 4 THEN UPDATE employees SET salary = salary + 400 WHERE employee_id = emp_id;
ELSE UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
END CASE;
END //
DELIMITER ;
循環(huán)結(jié)構(gòu)之LOOP
LOOP循環(huán)語句用來重復執(zhí)行某些語句。LOOP內(nèi)的語句一直重復執(zhí)行直到循環(huán)被退出(使用LEAVE子句),跳出循環(huán)過程。
LOOP語句的基本格式如下:
]LOOP
:循環(huán)執(zhí)行的語句
END LOOP [loop_label]
其中,loop_label表示LOOP語句的標注名稱,該參數(shù)可以省略。
#舉例1:
DELIMITER //
CREATE PROCEDURE test_loop()
BEGIN
#聲明局部變量
DECLARE num INT DEFAULT 1;
loop_label:LOOP
#重新賦值
SET num = num + 1;
#可以考慮某個代碼程序反復執(zhí)行。(略)
IF num >= 10 THEN LEAVE loop_label;
END IF;
END LOOP loop_label;
#查看num
SELECT num;
END //
DELIMITER ;
#舉例2:當市場環(huán)境變好時,公司為了獎勵大家,決定給大家漲工資。
#聲明存儲過程“update_salary_loop()”,聲明OUT參數(shù)num,輸出循環(huán)次數(shù)。
#存儲過程中實現(xiàn)循環(huán)給大家漲薪,薪資漲為原來的1.1倍。直到全公司的平
#均薪資達到12000結(jié)束。并統(tǒng)計循環(huán)次數(shù)。
DELIMITER //
CREATE PROCEDURE update_salary_loop(OUT num INT)
BEGIN
#聲明變量
DECLARE avg_sal DOUBLE ; #記錄員工的平均工資
DECLARE loop_count INT DEFAULT 0;#記錄循環(huán)的次數(shù)
#① 初始化條件
#獲取員工的平均工資
SELECT AVG(salary) INTO avg_sal FROM employees;
loop_lab:LOOP
#② 循環(huán)條件
#結(jié)束循環(huán)的條件
IF avg_sal >= 12000
THEN LEAVE loop_lab;
END IF;
#③ 循環(huán)體
#如果低于12000,更新員工的工資
UPDATE employees SET salary = salary * 1.1;
#④ 迭代條件
#更新avg_sal變量的值
SELECT AVG(salary) INTO avg_sal FROM employees;
#記錄循環(huán)次數(shù)
SET loop_count = loop_count + 1;
END LOOP loop_lab;
#給num賦值
SET num = loop_count;
END //
DELIMITER ;
SELECT AVG(salary) FROM employees;
CALL update_salary_loop(@num);
SELECT @num;
循環(huán)結(jié)構(gòu)之WHILE
WHILE語句創(chuàng)建一個帶條件判斷的循環(huán)過程。WHILE在執(zhí)行語句執(zhí)行時,先對指定的表達式進行判斷,如果為真,就執(zhí)行循環(huán)內(nèi)的語句,否則退出循環(huán)。
WHILE語句的基本格式如下:
] WHILE 循環(huán)條件 DO
: 循環(huán)體
END WHILE [while_label];
while_label為WHILE語句的標注名稱;如果循環(huán)條件結(jié)果為真,WHILE語句內(nèi)的語句或語句群被執(zhí)行,直至循環(huán)條件為假,退出循環(huán)。
#舉例1:
DELIMITER //
CREATE PROCEDURE test_while()
BEGIN
#初始化條件
DECLARE num INT DEFAULT 1;
#循環(huán)條件
WHILE num <= 10 DO
#循環(huán)體(略)
#迭代條件
SET num = num + 1;
END WHILE;
#查詢
SELECT num;
END //
DELIMITER ;
#調(diào)用
CALL test_while();
#舉例2:市場環(huán)境不好時,公司為了渡過難關,決定暫時降低大家的薪資。
#聲明存儲過程“update_salary_while()”,聲明OUT參數(shù)num,輸出循環(huán)次數(shù)。
#存儲過程中實現(xiàn)循環(huán)給大家降薪,薪資降為原來的90%。直到全公司的平均薪資
#達到5000結(jié)束。并統(tǒng)計循環(huán)次數(shù)。
DELIMITER //
CREATE PROCEDURE update_salary_while(OUT num INT)
BEGIN
#聲明變量
DECLARE avg_sal DOUBLE ; #記錄平均工資
DECLARE while_count INT DEFAULT 0; #記錄循環(huán)次數(shù)
#賦值
SELECT AVG(salary) INTO avg_sal FROM employees;
WHILE avg_sal > 5000 DO
UPDATE employees SET salary = salary * 0.9 ;
SET while_count = while_count + 1;
SELECT AVG(salary) INTO avg_sal FROM employees;
END WHILE;
#給num賦值
SET num = while_count;
END //
DELIMITER ;
#調(diào)用
CALL update_salary_while(@num);
SELECT @num;
SELECT AVG(salary) FROM employees;
循環(huán)結(jié)構(gòu)之REPEAT
REPEAT語句創(chuàng)建一個帶條件判斷的循環(huán)過程。與WHILE循環(huán)不同的是,REPEAT循環(huán)首先會執(zhí)行一次循環(huán),然后在UNTIL中進行表達式的判斷
如果滿足條件就退出,即ENDREPEAT;如果條件不滿足,則會就繼續(xù)執(zhí)行循環(huán),直到滿足退出條件為止。
REPEAT語句的基本格式如下:
] REPEAT
:循環(huán)體的語句
UNTIL 結(jié)束循環(huán)的條件表達式
END REPEAT [repeat_label]
repeat_label為REPEAT語句的標注名稱,該參數(shù)可以省略;REPEAT語句內(nèi)的語句或語句群被重復,直至expr_condition為真。
#舉例1:
DELIMITER //
CREATE PROCEDURE test_repeat()
BEGIN
#聲明變量
DECLARE num INT DEFAULT 1;
REPEAT
SET num = num + 1;
UNTIL num >= 10
END REPEAT;
#查看
SELECT num;
END //
DELIMITER ;
#調(diào)用
CALL test_repeat();
#舉例2:當市場環(huán)境變好時,公司為了獎勵大家,決定給大家漲工資。
#聲明存儲過程“update_salary_repeat()”,聲明OUT參數(shù)num,輸出循環(huán)次數(shù)。
#存儲過程中實現(xiàn)循環(huán)給大家漲薪,薪資漲為原來的1.15倍。直到全公司的平均
#薪資達到13000結(jié)束。并統(tǒng)計循環(huán)次數(shù)。
DELIMITER //
CREATE PROCEDURE update_salary_repeat(OUT num INT)
BEGIN
#聲明變量
DECLARE avg_sal DOUBLE ; #記錄平均工資
DECLARE repeat_count INT DEFAULT 0; #記錄循環(huán)次數(shù)
#賦值
SELECT AVG(salary) INTO avg_sal FROM employees;
REPEAT
UPDATE employees SET salary = salary * 1.15;
SET repeat_count = repeat_count + 1;
SELECT AVG(salary) INTO avg_sal FROM employees;
UNTIL avg_sal >= 13000
END REPEAT;
#給num賦值
SET num = repeat_count;
END //
DELIMITER ;
#調(diào)用
CALL update_salary_repeat(@num);
SELECT @num;
SELECT AVG(salary) FROM employees;
對比三種循環(huán)結(jié)構(gòu)
1、這三種循環(huán)都可以省略名稱,但如果循環(huán)中添加了循環(huán)控制語句(LEAVE或ITERATE)則必須添加名稱。2、LOOP:一般用于實現(xiàn)簡單的"死"循環(huán) WHILE:先判斷后執(zhí)行 REPEAT:先執(zhí)行后判斷,無條件至少執(zhí)行一次
跳轉(zhuǎn)語句之LEAVE
LEAVE語句:可以用在循環(huán)語句內(nèi),或者以BEGIN和END包裹起來的程序體內(nèi),表示跳出循環(huán)或者跳出程序體的操作。
如果你有面向過程的編程語言的使用經(jīng)驗,你可以把LEAVE理解為break。
基本格式如下:
LEAVE 標記名
其中,label參數(shù)表示循環(huán)的標志。LEAVE和BEGIN...END或循環(huán)一起被使用。
舉例1:創(chuàng)建存儲過程“l(fā)eave_begin()”,聲明INT類型的IN參數(shù)num。給BEGIN...END加標記名,并在BEGIN...END中使用IF語句判斷num參數(shù)的值。
如果num<=0,則使用LEAVE語句退出BEGIN...END;
如果num=1,則查詢“employees”表的平均薪資;
如果num=2,則查詢“employees”表的最低薪資;
如果num>2,則查詢“employees”表的最高薪資。
IF語句結(jié)束后查詢“employees”表的總?cè)藬?shù)。
DELIMITER //
CREATE PROCEDURE leave_begin(IN num INT)
begin_label:BEGIN
IF num <= 0
THEN LEAVE begin_label;
ELSEIF num = 1
THEN SELECT AVG(salary) FROM employees;
ELSEIF num = 2
THEN SELECT MIN(salary) FROM employees;
ELSE
SELECT MAX(salary) FROM employees;
END IF;
#查詢總?cè)藬?shù)
SELECT COUNT(*) FROM employees;
END //
DELIMITER ;
#調(diào)用
CALL leave_begin(1);
#舉例2:當市場環(huán)境不好時,公司為了渡過難關,決定暫時降低大家的薪資。
#聲明存儲過程“l(fā)eave_while()”,聲明OUT參數(shù)num,輸出循環(huán)次數(shù),存儲過程中使用WHILE
#循環(huán)給大家降低薪資為原來薪資的90%,直到全公司的平均薪資小于等于10000,并統(tǒng)計循環(huán)次數(shù)。
DELIMITER //
CREATE PROCEDURE leave_while(OUT num INT)
BEGIN
DECLARE avg_sal DOUBLE;#記錄平均工資
DECLARE while_count INT DEFAULT 0; #記錄循環(huán)次數(shù)
SELECT AVG(salary) INTO avg_sal FROM employees; #① 初始化條件
while_label:WHILE TRUE DO #② 循環(huán)條件
#③ 循環(huán)體
IF avg_sal <= 10000 THEN
LEAVE while_label;
END IF;
UPDATE employees SET salary = salary * 0.9;
SET while_count = while_count + 1;
#④ 迭代條件
SELECT AVG(salary) INTO avg_sal FROM employees;
END WHILE;
#賦值
SET num = while_count;
END //
DELIMITER ;
#調(diào)用
CALL leave_while(@num);
SELECT @num;
SELECT AVG(salary) FROM employees;
跳轉(zhuǎn)語句之ITERATE
ITERATE語句:只能用在循環(huán)語句(LOOP、REPEAT和WHILE語句)內(nèi),表示重新開始循環(huán),將執(zhí)行順序轉(zhuǎn)到語句段開頭處。
如果你有面向過程的編程語言的使用經(jīng)驗,你可以把ITERATE理解為continue,意思為“再次循環(huán)”。
語句基本格式如下:
ITERATE label
label參數(shù)表示循環(huán)的標志。ITERATE語句必須跟在循環(huán)標志前面。
舉例:定義局部變量num,初始值為0。循環(huán)結(jié)構(gòu)中執(zhí)行num+1操作。
如果num<10,則繼續(xù)執(zhí)行循環(huán);
如果num>15,則退出循環(huán)結(jié)構(gòu);
DELIMITER //
CREATE PROCEDURE test_iterate()
BEGIN
DECLARE num INT DEFAULT 0;
loop_label:LOOP
#賦值
SET num = num + 1;
IF num < 10
THEN ITERATE loop_label;
ELSEIF num > 15
THEN LEAVE loop_label;
END IF;
SELECT '尚硅谷:讓天下沒有難學的技術';
END LOOP;
END //
DELIMITER ;
CALL test_iterate();
SELECT * FROM employees;
練習
#1. 創(chuàng)建函數(shù)test_if_case(),實現(xiàn)傳入成績,如果成績>90,返回A,如果成績>80,返回B,如果成績>60,返回C,否則返回D
#要求:分別使用if結(jié)構(gòu)和case結(jié)構(gòu)實現(xiàn)
#方式1:
DELIMITER //
CREATE FUNCTION test_if_case1(score DOUBLE)
RETURNS CHAR
BEGIN
DECLARE ch CHAR;
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 //
DELIMITER ;
#調(diào)用
SELECT test_if_case1(87);
#方式2:
DELIMITER //
CREATE FUNCTION test_if_case2(score DOUBLE)
RETURNS CHAR
BEGIN
DECLARE ch CHAR;
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 //
DELIMITER ;
#調(diào)用
SELECT test_if_case2(67);
#2. 創(chuàng)建存儲過程test_if_pro(),傳入工資值,如果工資值<3000,則刪除工資為此值的員工,如果3000 <= 工資值 <= 5000,則修改此工資值的員工薪資漲1000,否則漲工資500
DELIMITER //
CREATE PROCEDURE test_if_pro(IN sal DOUBLE)
BEGIN
IF sal<3000
THEN DELETE FROM employees WHERE salary = sal;
ELSEIF sal <= 5000
THEN UPDATE employees SET salary = salary+1000 WHERE salary = sal;
ELSE
UPDATE employees SET salary = salary+500 WHERE salary = sal;
END IF;
END //
DELIMITER ;
SELECT * FROM employees;
#調(diào)用
CALL test_if_pro(3100);
#3. 創(chuàng)建存儲過程insert_data(),傳入?yún)?shù)為 IN 的 INT 類型變量 insert_count,實現(xiàn)向admin表中批量插
入insert_count條記錄
DELIMITER //
CREATE PROCEDURE insert_data(IN insert_count INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= insert_count DO
INSERT INTO admin(user_name,user_pwd) VALUES(CONCAT('Rose-',i),ROUND(RAND() * 100000));
SET i=i+1;
END WHILE;
END //
DELIMITER ;
#調(diào)用
CALL insert_data(100);
-
控制
+關注
關注
4文章
1011瀏覽量
122682 -
MySQL
+關注
關注
1文章
816瀏覽量
26614 -
IF
+關注
關注
1文章
50瀏覽量
26879
原文標題:mysql8.0流程控制一文拿捏
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論