最近又複習了mysql中的一些概念:視圖,觸發器,存儲過程,函數,事務,記錄下。html
1.視圖前端
視圖是一個虛擬表,自己並不存儲數據,當sql在操做視圖時全部數據都是從其餘表中查出來的,所以其本質是:根據SQL語句獲取動態的數據集,併爲其命名,用戶使用時只需使用【名稱】便可獲取結果集,並能夠將其看成表來使用。python
視圖操做:mysql
-- CREATE TABLE students( -- nid INT NOT NULL AUTO_INCREMENT, -- name VARCHAR(128) NOT NULL, -- gender CHAR(8) NOT NULL, -- age INT NOT NULL, -- class VARCHAR(64) NOT NULL, -- PRIMARY KEY (nid) -- )DEFAULT CHARSET=utf8; -- INSERT INTO students(name, gender,age,class) VALUES('李木','男',24,'python班'); -- INSERT INTO students(name, gender,age,class) -- VALUES('王華','男',26,'python班'), -- ('王鈺','女',22,'前端'); -- 建立並使用視圖view1 -- SELECT * FROM (SELECT nid,name FROM students WHERE nid>1) AS view1 WHERE view1.name="王華"; -- 建立視圖格式: CREATE VIEW 視圖名稱 AS sql語句; -- CREATE VIEW view1 AS SELECT nid, name FROM students WHERE nid>1; -- 修改視圖格式:ALTER VIEW 視圖名稱 AS sql語句; -- ALTER VIEW view1 AS SELECT nid,name FROM students WHERE name="李木"; -- 使用視圖:使用視圖時,將其看成表進行操做便可,因爲視圖是虛擬表,因此沒法使用其對真實表進行建立、更新和刪除操做,僅能作查詢用。 -- SELECT * FROM view1; -- 刪除視圖格式:DROP VIEW 視圖名稱; -- DROP VIEW view1;
2.觸發器git
對某個表行進行增刪改操做,若是但願操做先後觸發某些特定的操做,即可以使用觸發器。觸發器就像信號或中間件相似,能夠定製特定的操做,注意的是行操做觸發。github
觸發器操做:算法
-- 建立觸發器語法
每一行插入前觸發
CREATE TRIGGER tri_before_insert_table BEFORE INSERT ON students FOR EACH ROW;
BEGIN
END
插入後觸發
CREATE TRIGGER tri_after_insert_table AFTER INSERT ON students FOR EACH ROW;
BEGIN
END
刪除前觸發
CREATE TRIGGER tri_before_delete_table BEFORE DELETE ON students FOR EACH ROW;
BEGIN
END
刪除後觸發
CREATE TRIGGER tri_after_delete_table AFTER DELETE ON students FOR EACH ROW;
BEGIN
END
更新前觸發
CREATE TRIGGER tri_before_update_table BEFORE UPDATE ON students FOR EACH ROW;
BEGIN
ON
更新後觸發
CREATE TRIGGER tri_after_update_table AFTER UPDATE ON students FOR EACH ROW;
BEGIN
觸發器使用示例sql
CREATE TABLE class( nid INT NOT NULL AUTO_INCREMENT, name VARCHAR(64) NOT NULL, count INT NOT NULL, PRIMARY KEY (nid) ) DEFAULT CHARSET = utf8 INSERT INTO class(name,count) VALUES("python班",45),("算法班",50); 建立插入前觸發器 NEW表示即將新插入的行 delimiter // CREATE TRIGGER tri_before_insert BEFORE INSERT ON students FOR EACH ROW BEGIN IF NEW.class = "前端" THEN INSERT INTO class ( name,count ) VALUES ( "前端",1 ) ; END IF; END// delimiter; 建立插入後觸發器 delimiter // CREATE TRIGGER tri_after_insert AFTER INSERT ON students FOR EACH ROW BEGIN IF NEW.class="python" THEN INSERT INTO class(name,count) VALUES("python",1); ELSEIF NEW.class = "數據結構" THEN INSERT INTO class(name,count) VALUES("數據結構",2); END IF; END// delimiter; 使用觸發器(插入一行數據時觸發) insert into students(name,gender,age,class)values('李曼',"女",25,"python"); insert into students(name,gender,age,class)values('王軍',"男",25,"數據結構"); 刪除觸發器 DROP TRIGGER tri_before_insert;
(觸發器中,NEW表示即將插入的數據行,OLD表示即將刪除的數據行。)數據庫
觸發器性能:https://segmentfault.com/q/1010000004907411segmentfault
https://www.cnblogs.com/geaozhang/p/6819648.html
3. 存儲過程
存儲過程是一組SQL語句集合,通過編譯建立並保存在數據庫中,用戶能夠經過指定存儲過程的名字並給定參數(若須要時)來調用。當調用存儲過程時,其內部的SQL語句會按邏輯順序執行。
建立存儲過程:
--建立存儲過程 delimiter // CREATE PROCEDURE p1() BEGIN SELECT * FROM students WHERE class = "前端"; END // delimiter; --調用存儲過程 call p1()
存儲過程還能夠接受參數,包括三類參數:
-- 傳入和傳出參數 delimiter // CREATE PROCEDURE p2( IN i1 INT, IN i2 INT, INOUT i3 INT, OUT i4 INT ) BEGIN DECLARE temp1 INT; DECLARE temp2 INT DEFAULT 0; SET temp1=1; SET i4 =i1+i2+temp1+temp2; set i3 = i3+100; END// delimiter; -- 執行存儲過程p2() SET @t1=4; SET @t2=5; CALL p2(1,2,@t1,@t2); SELECT @t1,@t2; -- 輸出結果 -- @t1,@t2 -- 104, 4
經過存儲過程的返回值,能夠用來判斷其執行狀態,以下:
-- 支持事務(經過返回值能判斷執行的狀態) delimiter// CREATE PROCEDURE p3( OUT p_return_code TINYINT ) BEGIN -- 出現錯誤 DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN set p_return_code=1; ROLLBACK; END; -- 出現警告 DECLARE EXIT HANDLER FOR SQLWARNING BEGIN set p_return_code=2; ROLLBACK; END; START TRANSACTION; DELETE FROM class; INSERT INTO students(name,gender,age,class) VALUES("宋紅雲","女",23,"python"); COMMIT; -- 成功執行 SET p_return_code = 0; END// delimiter; SET @r1 = -1; CALL p3(@r1); SELECT @r1; -- 輸出結果 @r1=0
存儲過程使用遊標
-- 使用遊標 delimiter// CREATE PROCEDURE p4() BEGIN DECLARE sage INT; DECLARE sname VARCHAR(128); DECLARE done INT DEFAULT FALSE; DECLARE my_cursor CURSOR FOR SELECT name,age FROM students; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done =TRUE; OPEN my_cursor; myloop: LOOP FETCH my_cursor INTO sname,sage; IF done THEN LEAVE myloop; END IF; INSERT INTO class(cname) values(sname); END LOOP myloop; CLOSE my_cursor; END// delimiter; CALL p4();
利用prepare,execute,dellocate, 能夠實現動態執行SQL語句,同時對SQL語句進行檢查,防治SQL注入(?爲查詢條件中佔位符)
delimiter// CREATE PROCEDURE p5( IN i INT ) BEGIN SET @i2 = i; PREPARE prod FROM "select * from students where nid=? "; EXECUTE prod USING @i2; -- 變量只能是SET @i2 = value的變量,傳入和declare的變量不行 DEALLOCATE PREPARE prod; END// delimiter; CALL p5(2); -- sql注入: -- sql = "select * from students where name="+i+";" -- 若是採用上面字符竄拼接sql語句時,當用戶輸入的i="ss or 1=1",則where語句確定爲TRUE,會拿到全部的name數據
上述語句中注意EXECUTE prod USING @i1,@i2;能夠傳入多個查詢變量,和佔位符按順序對應,並且變量只能是變量只能是SET @i2 = value的變量,傳入和declare的變量不行。
python中經過pymysql模塊也能夠調用存儲過程
#coding:utf-8 import pymysql conn = pymysql.connect(host="localhost",port=3306,db="learningsql",user="root",passwd="",charset="utf8") cursor = conn.cursor() #cursor = conn.cursor(cursor = pymysql.cursors.DictCursors) 最後返回的結果,每一行爲字典 cursor.callproc("p5",args=(1,)) #執行須要參數的存儲過程 # a,b=0,0 # cursor.callproc("p2",args=(1,2,a,b)) # cursor.execute("select @_p2_0,@_p2_1,@_p2_3,@_p2_4") #拿到第1,2,3,4個參數。。。。 result = cursor.fetchall() cursor.close() conn.close() print(result)
4.函數
內置函數:https://dev.mysql.com/doc/refman/5.7/en/functions.html(官方文檔)
經常使用內置函數
CHAR_LENGTH(str) 返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算做一個單字符。 對於一個包含五個二字節字符集, LENGTH()返回值爲 10, 而CHAR_LENGTH()的返回值爲5。 length: 是計算字段的長度,一個漢字是算兩個或三個字符,一個數字或字母算一個字符; char_length:無論漢字仍是數字或者是字母都算是一個字符; CONCAT(str1,str2,...) 字符串拼接 若有任何一個參數爲NULL ,則返回值爲 NULL。 CONCAT_WS(separator,str1,str2,...) 字符串拼接(自定義鏈接符) CONCAT_WS()不會忽略任何空字符串。 (然而會忽略全部的 NULL)。 CONV(N,from_base,to_base) 進制轉換 例如: SELECT CONV('a',16,2); 表示將 a 由16進制轉換爲2進制字符串表示 FORMAT(X,D) 將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字符串的形式返回。若 D 爲 0, 則返回結果不帶有小數點,或不含小數部分。 例如: SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000' INSERT(str,pos,len,newstr) 在str的指定位置插入字符串 pos:要替換位置其實位置 len:替換的長度 newstr:新字符串 特別的: 若是pos超過原字符串長度,則返回原字符串 若是len超過原字符串長度,則由新字符串徹底替換 INSTR(str,substr) 返回字符串 str 中子字符串的第一個出現位置。 LEFT(str,len) 返回字符串str 從開始的len位置的子序列字符。 LOWER(str) 變小寫 UPPER(str) 變大寫 LTRIM(str) 返回字符串 str ,其引導空格字符被刪除。 RTRIM(str) 返回字符串 str ,結尾空格字符被刪去。 SUBSTRING(str,pos,len) 獲取字符串子序列 LOCATE(substr,str,pos) 獲取子序列索引位置 REPEAT(str,count) 返回一個由重複的字符串str 組成的字符串,字符串str的數目等於count 。 若 count <= 0,則返回一個空字符串。 若str 或 count 爲 NULL,則返回 NULL 。 REPLACE(str,from_str,to_str) 返回字符串str 以及全部被字符串to_str替代的字符串from_str 。 REVERSE(str) 返回字符串 str ,順序和字符順序相反。 RIGHT(str,len) 從字符串str 開始,返回從後邊開始len個字符組成的子序列 SPACE(N) 返回一個由N空格組成的字符串。 SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len) 不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值。 mysql> SELECT SUBSTRING('Quadratically',5); -> 'ratically' mysql> SELECT SUBSTRING('foobarbar' FROM 4); -> 'barbar' mysql> SELECT SUBSTRING('Quadratically',5,6); -> 'ratica' mysql> SELECT SUBSTRING('Sakila', -3); -> 'ila' mysql> SELECT SUBSTRING('Sakila', -5, 3); -> 'aki' mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2); -> 'ki' TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str) 返回字符串 str , 其中全部remstr 前綴和/或後綴都已被刪除。若分類符BOTH、LEADIN或TRAILING中沒有一個是給定的,則假設爲BOTH 。 remstr 爲可選項,在未指定狀況下,可刪除空格。 mysql> SELECT TRIM(' bar '); -> 'bar' mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx'); -> 'barxxx' mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx'); -> 'bar' mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz'); -> 'barx' 部份內置函數
自定義函數
-- 定義函數,注意定義返回值類型 delimiter \\ CREATE FUNCTION fun( i1 INT, i2 INT ) RETURNS INT BEGIN DECLARE sum INT; SET sum = i1+i2; RETURN(sum); END \\ delimiter ; -- -- 經過select使用 SELECT fun(1,2); -- -- 對查詢表字段進行函數操做 SELECT name,fun(1,age) from students; -- 將函數結果存儲到變量 SELECT fun(1,2) INTO @sum; SELECT @sum; SELECT UPPER("zack") INTO @name; SELECT @name; -- 刪除函數 DROP FUNCTION fun;
自定義函數時注意用戶變量,局部變量,全局變量,會話變量,參考:https://blog.csdn.net/qq_34626097/article/details/86528466
5.事務
事務是知足 ACID 特性的一組操做,要麼所有執行,要麼所有不執行,能夠經過 Commit 提交一個事務,也可使用 Rollback 進行回滾。在mysql中,事務用於將某些操做的多個SQL操做做爲原子性操做,一旦有某一個出現錯誤,便可回滾到原來的狀態,從而保證數據庫數據完整性。
原子性(Atomicity):事務被視爲不可分割的最小單位,要麼所有執行成功,要麼所有失敗,進行回滾。(回滾能夠經過回滾日誌實現,回滾日誌記錄着事務所執行的修改操做,在回滾時反向執行這些修改操做便可。)
一致性(Consistency):數據庫在事務執行先後都保持一致性狀態。在一致性狀態下,全部事務對一個數據的讀取結果都是相同的。
隔離性(Isolation):一個事務所作修改在最終提交前,對其餘事務是不可見的。多個事務併發執行時互不影響。
持久性(Durability):一但事務提交,其所作的修改將永遠保存在數據庫中,即便系統發生崩潰,事務執行的結果也不能丟失。(能夠用重作日誌來保證持久性)
對ACID特性的理解:(幾個特性不是一種平級關係)
ACID特性
一致性狀態和中間狀態
5.1 事務的併發一致性問題
在多併發條件下,多個事務的隔離性很難保證,所以會出現不少併發一致性問題,包括丟失修改,髒讀,不可重複讀,幻讀。
丟失修改:事務T1和T2都修改了數據,T1先修改,T2後修改,T2的修改覆蓋了T1的修改。
髒讀:事務T1修改了數據,事務T2讀取了修改後的數據。隨後T1回滾撤銷了修改,事務T2讀取到的就是髒數據。
不可重複讀:事務T2讀取一個數據,T1對數據作了修改,若是T2再次 讀取這個數據,此時讀取的結果和第一次不一致。
幻讀:T1讀取某個範圍的數據,T2在這個範圍了插入了一條數據,T1再次讀取這個範圍了數據,和第一次讀取的結果不一樣。
(場景:系統管理員A將數據庫中全部學生的成績從具體分數改成ABCDE等級,可是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺同樣,這就叫幻讀。)
5.2 事務的隔離級別
上述的併發一致性問題是因爲破壞了事務的隔離性,得經過併發控制來保證事務的隔離性。數據庫管理系統提供了事務的隔離級別來處理併發一致性問題,包括未提交讀(read uncommitted),提交讀(read committed),可重複讀(repeated read),可串行化(serilization)。(併發控制能夠經過封鎖來實現,可是封鎖操做須要用戶本身控制,至關複雜。)
未提交讀:最低的隔離級別,什麼都不須要作,一個事務能夠讀到另外一個事務未提交的結果。全部的併發事務問題都會發生
提交讀:只有在事務提交後,其更新結果纔會被其餘事務看見。能夠解決髒讀問題。
可重複讀:在一個事務中,對於同一份數據的讀取結果老是相同的,不管是否有其餘事務對這份數據進行操做,以及事務是否提交。能夠解決髒讀、不可重複讀。
可串行化:事務串行化執行,隔離級別最高,犧牲了系統的併發性。能夠解決併發事務的全部問題。
5.3 多版本併發控制(MVCC,Multi-Version Concurrent Control)
多版本併發控制是MySQL的InnoDB提供的一種實現隔離級別的具體方式。MVCC能夠用於實現提交讀和可重複讀。未提交讀隔離級別,老是讀取最新的數據行,無需使用 MVCC。可串行化須要對全部讀取的行都加鎖,單純使用 MVCC 沒法實現。(一句話講,MVCC就是同一份數據臨時保留多個版本/快照)
MVCC實現機制
1.版本號:
系統版本號:是一個遞增的數字,每開始一個新的事務,系統版本號就會自動遞增。(包含insert、delete和update操做的事務)
事務版本號:事務開始時的系統版本號。
2.隱藏的列
MVCC 在每行記錄後面都保存着兩個隱藏的列,用來存儲兩個版本號:建立版本號和刪除版本號
建立版本號:對該行數據建立操做時的事務版本號
刪除版本號:對該行數據進行刪除操做時的事務版本號
3.實現過程(可重複讀隔離級別)
因爲舊數據並不真正的刪除,因此必須對這些數據進行清理,innodb會開啓一個後臺線程執行清理工做,具體的規則是將刪除版本號小於當前系統版本的行刪除,這個過程叫作purge。
4.undo日誌
MVCC 使用到的快照存儲在 Undo 日誌中,該日誌經過回滾指針把一個數據行(Record)的全部快照鏈接起來。
(TRX_ID: 事務版本號,爲3時表示最新版本快照,經過回滾指針依次指向2,1,版本號)
5.4 Next-key locks
參考:https://www.cnblogs.com/zhoujinyi/p/3435982.html
http://hedengcheng.com/?p=771
https://zhuanlan.zhihu.com/p/35477890
Next-Key Locks是MySQL的InnoDb的一種鎖實現。MVCC不能解決幻讀問題,Next-Key Locks 就是爲了解決這個問題而存在的。在可重複讀隔離級別下,MVCC+Next-Key Locks能夠解決幻讀問題。Next-Key Locks是Record Locks和Gap Locks的結合。
Record Locks:鎖定一個記錄上的索引,而不是記錄自己。(若是表沒有設置索引,InnoDB 會自動在主鍵上建立隱藏的聚簇索引,所以 Record Locks 依然可使用。)
Gap Locks:鎖定索引之間的間隙,可是不包含索引自己。例如當一個事務執行如下語句,其它事務就不能在 t.c 中插入 15。
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
Next-Key Locks:不只鎖定一個記錄上的索引,也鎖定索引之間的間隙。例如一個索引包含如下值:10, 11, 13, and 20,那麼就須要鎖定如下區間:
(negative infinity, 10]
(10, 11] (11, 13] (13, 20] (20, positive infinity)
索引在[10,20]區間會被鎖定,鎖定後對該區間的操做都會被阻塞
5.5 封鎖
5.5.1封鎖粒度:
MySQL提供了兩種封鎖粒度:行級鎖和表級鎖。 在選擇封鎖粒度時,須要在鎖開銷和併發程度之間作一個權衡。由於鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。可是加鎖須要消耗資源,鎖的各類操做(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增長系統開銷。所以封鎖粒度越小,系統開銷就越大。
5.5.2封鎖類型:
a.讀寫鎖:
排它鎖(Exclusive),簡寫爲 X 鎖,又稱寫鎖。
一個事務對數據對象 A 加了 X 鎖,就能夠對 A 進行讀取和更新。加鎖期間其它事務不能對 A 加任何鎖。
共享鎖(Shared),簡寫爲 S 鎖,又稱讀鎖。
一個事務對數據對象 A 加了 S 鎖,能夠對 A 進行讀取操做,可是不能進行更新操做。加鎖期間其它事務能對 A 加 S 鎖,可是不能加 X 鎖。
兼容性
b .意向鎖:
使用意向鎖(Intention Locks)能夠更容易地支持多粒度封鎖。
在存在行級鎖和表級鎖的狀況下,事務 T 想要對錶 A 加 X 鎖,就須要先檢測是否有其它事務對錶 A 或者表 A 中的任意一行加了鎖,那麼就須要對錶 A 的每一行都檢測一次,這是很是耗時的。
意向鎖在原來的 X/S 鎖之上引入了 IX/IS,IX/IS 都是表鎖,用來表示一個事務想要在表中的某個數據行上加 X 鎖或 S 鎖。有如下兩個規定:
1. 一個事務在得到某個數據行對象的 S 鎖以前,必須先得到表的 IS 鎖或者更強的鎖;
2. 一個事務在得到某個數據行對象的 X 鎖以前,必須先得到表的 IX 鎖。
經過引入意向鎖,事務 T 想要對錶 A 加 X 鎖,只須要先檢測是否有其它事務對錶 A 加了 X/IX/S/IS 鎖,若是加了就表示有其它事務正在使用這個表或者表中某一行的鎖,所以事務 T 加 X 鎖失敗。
兼容性:
任意 IS/IX 鎖之間都是兼容的,由於它們只是表示想要對錶加鎖,而不是真正加鎖;
S 鎖只與 S 鎖和 IS 鎖兼容,也就是說事務 T 想要對數據行加 S 鎖,其它事務能夠已經得到對錶或者表中的行的 S 鎖。
5.5.3封鎖協議:
參考:https://yq.aliyun.com/articles/626848
https://yq.aliyun.com/articles/626848
a.三級封鎖協議
一級封鎖協議:事務T修改數據時必須加X鎖,直到T結束才能釋放。由於不能同時有兩個事務對數據修改,能夠解決丟失修改問題
二級封鎖協議:在一級的基礎上,要求讀數據A時必須加S鎖,讀完立刻釋放鎖。由於一個事務對數據A修改時會加X鎖,就不會再加S鎖,不能 讀取數據,能夠解決髒讀問題。
三級封鎖協議:在二級的基礎上,要求讀取數據A時必須加S鎖,直到事務結束時才能釋放鎖。由於讀數據A時一直有S鎖,不能再加X鎖,保證了 數據不會改變,能夠解決不可重複讀問題
b.兩段鎖協議:加鎖和解鎖分爲兩個階段進行。
可串行化調度是指,經過併發控制,使得併發執行的事務結果與某個串行執行的事務結果相同。
事務遵循兩段鎖協議是保證可串行化調度的充分條件
5.5.4隱式鎖和顯式鎖:MySQL 的 InnoDB 存儲引擎採用兩段鎖協議,會根據隔離級別在須要的時候自動加鎖,而且全部的鎖都是在同一時刻被釋放,這被 稱爲隱式鎖定。InnoDB 也可使用特定的語句進行顯示鎖定。(SELECT ... LOCK In SHARE MODE;)
5.6 事務語句
start transaction........commit;
失敗時rollback
delimiter \\ create PROCEDURE p1( OUT p_return_code tinyint ) BEGIN DECLARE exit handler for sqlexception BEGIN -- ERROR set p_return_code = 1; rollback; END; DECLARE exit handler for sqlwarning BEGIN -- WARNING set p_return_code = 2; rollback; END; START TRANSACTION; DELETE from tb1; insert into tb2(name)values('seven'); COMMIT; -- SUCCESS set p_return_code = 0; END\\ delimiter ; 使用事務 set @i=-1; call p1(@i); select @i;
6.條件判斷和循環語句
條件語句:if..then.;.elseif.then.;.else..;.end if;
-- 條件判斷語句 delimiter \\ CREATE PROCEDURE p1( IN i INT ) BEGIN IF i = 2 THEN SELECT * FROM students WHERE nid=2; ELSEIF i>2 THEN SELECT * FROM students WHERE nid>2; ELSE SELECT * FROM students WHERE nid<2; END IF; END\\ delimiter ; CALL p1(2);
循環語句:while循環,repeat循環,loop循環
-- while 循環語句 delimiter \\ CREATE PROCEDURE p2( IN i INT ) BEGIN DECLARE sum INT; SET sum = 0; WHILE sum<10 DO SELECT sum; SET sum = sum +i; END WHILE; END \\ delimiter ; CALL p2(1);
-- repeat 循環 delimiter \\ CREATE PROCEDURE p3() BEGIN DECLARE i INT; SET i = 0; REPEAT SET i = i+1; SELECT i; UNTIL i>3 END REPEAT; END \\ delimiter; CALL p3();
-- loop循環 delimiter \\ CREATE PROCEDURE p4() BEGIN DECLARE i INT DEFAULT 0; label: LOOP SET i = i+2; IF i=4 THEN SELECT * FROM students WHERE nid>4; END IF; IF i>6 THEN LEAVE label; END IF; SELECT i; END LOOP label; END \\ delimiter; CALL p4();
參考:http://www.cnblogs.com/wupeiqi/articles/5713323.html
https://github.com/CyC2018/CS-Notes