2020重新出發,MySql基礎,MySql檢視&索引&儲存過程&觸發器

夜雨流雲發表於2020-08-28

@

目錄

檢視是什麼

檢視在資料庫中的作用類似於窗戶,使用者可以通過這個視窗看到只對自己有用的資料。既保障了資料的安全性,又大大提高了查詢效率

MySQL 檢視(View)是一種虛擬存在的表,同真實表一樣,檢視也由列和行構成,但檢視並不實際存在於資料庫中。行和列的資料來自於定義檢視的查詢中所使用的表,並且還是在使用檢視時動態生成的。

資料庫中只存放了檢視的定義,並沒有存放檢視中的資料,這些資料都存放在定義檢視查詢所引用的真實表中。使用檢視查詢資料時,資料庫會從真實表中取出對應的資料。因此,檢視中的資料是依賴於真實表中的資料的。一旦真實表中的資料發生改變,顯示在檢視中的資料也會發生改變。

檢視可以從原有的表上選取對使用者有用的資訊,那些對使用者沒用,或者使用者沒有許可權瞭解的資訊,都可以直接遮蔽掉,作用類似於篩選。這樣做既使應用簡單化,也保證了系統的安全。

例如,下面的資料庫中有一張公司部門表 department。表中包括部門號(d_id)、部門名稱(d_name)、功能(function)和辦公地址(address)。department 表的結構如下:

mysql> DESC department;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| d_id     | int(4)      | NO   | PRI | NULL    |       |
| d_name   | varchar(20) | NO   | UNI    | NULL    |       |
| function | varchar(50) | YES  |     | NULL    |       |
| address  | varchar(50) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.02 sec)

還有一張員工表 worker。表中包含了員工的工作號(num)、部門號(d_id)、姓名(name)、性別(sex)、出生日期(birthday)和家庭住址(homeaddress)。worker 表的結構如下:

mysql> DESC worker;
+-------------+-------------+------+-----+---------+-------+
| Field       | Type        | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| num         | int(10)     | NO   | PRI | NULL    |       |
| d_id        | int(4)      | YES  |MUL     | NULL    |       |
| name        | varchar(20) | NO   |     | NULL    |       |
| sex         | varchar(4)  | NO   |     | NULL    |       |
| birthday    | datetime    | YES  |     | NULL    |       |
| homeaddress | varchar(50) | YES  |     | NULL    |       |
+-------------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

由於各部門領導的權力範圍不同,因此,各部門的領導只能看到該部門的員工資訊;而且,領導可能不關心員工的生日和家庭住址。為了達到這個目的,可以為各部門的領導建立一個檢視,通過該檢視,領導只能看到本部門員工的指定資訊。

  • 例如,為生產部門建立一個名為 product view 的檢視。通過檢視 product view,生產部門的領導只能看到生產部門員工的工作號、姓名和性別等資訊。這些 department 表的資訊和 worker 表的資訊依然存在於各自的表中,而檢視 product_view 中不儲存任何資料資訊。當 department 表和 worker 表的資訊發生改變時,檢視 product_view 顯示的資訊也會發生相應的變化。

技巧:如果經常需要從多個表查詢指定欄位的資料,可以在這些表上建立一個檢視,通過這個檢視顯示這些欄位的資料。

MySQL 的檢視不支援輸入引數的功能,因此互動性上還有欠缺。但對於變化不是很大的操作,使用檢視可以很大程度上簡化使用者的操作。

檢視並不同於資料表,它們的區別在於以下幾點:

  • 檢視不是資料庫中真實的表,而是一張虛擬表,其結構和資料是建立在對資料中真實表的查詢基礎上的。
  • 儲存在資料庫中的查詢操作 SQL 語句定義了檢視的內容,列資料和行資料來自於檢視查詢所引用的實際表,引用檢視時動態生成這些資料。
  • 檢視沒有實際的物理記錄,不是以資料集的形式儲存在資料庫中的,它所對應的資料實際上是儲存在檢視所引用的真實表中的。
  • 檢視是資料的視窗,而表是內容。表是實際資料的存放單位,而檢視只是以不同的顯示方式展示資料,其資料來源還是實際表。
  • 檢視是檢視資料表的一種方法,可以查詢資料表中某些欄位構成的資料,只是一些 SQL 語句的集合。從安全的角度來看,檢視的資料安全性更高,使用檢視的使用者不接觸資料表,不知道表結構。
  • 檢視的建立和刪除隻影響檢視本身,不影響對應的基本表。

檢視的優點

檢視與表在本質上雖然不相同,但檢視經過定義以後,結構形式和表一樣,可以進行查詢、修改、更新和刪除等操作。同時,檢視具有如下優點:

1) 定製使用者資料,聚焦特定的資料

在實際的應用過程中,不同的使用者可能對不同的資料有不同的要求。

例如,當資料庫同時存在時,如學生基本資訊表、課程表和教師資訊表等多種表同時存在時,可以根據需求讓不同的使用者使用各自的資料。學生檢視修改自己基本資訊的檢視,安排課程人員檢視修改課程表和教師資訊的檢視,教師檢視學生資訊和課程資訊表的檢視。

2) 簡化資料操作

在使用查詢時,很多時候要使用聚合函式,同時還要顯示其他欄位的資訊,可能還需要關聯到其他表,語句可能會很長,如果這個動作頻繁發生的話,可以建立檢視來簡化操作。

3) 提高資料的安全性

檢視是虛擬的,物理上是不存在的。可以只授予使用者檢視的許可權,而不具體指定使用表的許可權,來保護基礎資料的安全。

4) 共享所需資料

通過使用檢視,每個使用者不必都定義和儲存自己所需的資料,可以共享資料庫中的資料,同樣的資料只需要儲存一次。

5) 更改資料格式

通過使用檢視,可以重新格式化檢索出的資料,並組織輸出到其他應用程式中。

6) 重用 SQL 語句

檢視提供的是對查詢操作的封裝,本身不包含資料,所呈現的資料是根據檢視定義從基礎表中檢索出來的,如果基礎表的資料新增或刪除,檢視呈現的也是更新後的資料。檢視定義後,編寫完所需的查詢,可以方便地重用該檢視。

要注意區別檢視和資料表的本質,即檢視是基於真實表的一張虛擬的表,其資料來源均建立在真實表的基礎上。

使用檢視的時候,還應該注意以下幾點:

  • 建立檢視需要足夠的訪問許可權。
  • 建立檢視的數目沒有限制。
  • 檢視可以巢狀,即從其他檢視中檢索資料的查詢來建立檢視。
  • 檢視不能索引,也不能有關聯的觸發器、預設值或規則。
  • 檢視可以和表一起使用。
  • 檢視不包含資料,所以每次使用檢視時,都必須執行查詢中所需的任何一個檢索操作。如果用多個連線和過濾條件建立了複雜的檢視或巢狀了檢視,可能會發現系統執行效能下降得十分嚴重。因此,在部署大量檢視應用時,應該進行系統測試。

提示:ORDER BY 子句可以用在檢視中,但若該檢視檢索資料的 SELECT 語句中也含有 ORDER BY 子句,則該檢視中的 ORDER BY 子句將被覆蓋。

MySQL建立檢視

建立檢視是指在已經存在的 MySQL 資料庫表上建立檢視。檢視可以建立在一張表中,也可以建立在多張表中。

基本語法

可以使用 CREATE VIEW 語句來建立檢視。

語法格式如下:

CREATE VIEW <檢視名> AS <SELECT語句>

語法說明如下。

  • <檢視名>:指定檢視的名稱。該名稱在資料庫中必須是唯一的,不能與其他表或檢視同名。
  • <SELECT語句>:指定建立檢視的 SELECT 語句,可用於查詢多個基礎表或源檢視。

對於建立檢視中的 SELECT 語句的指定存在以下限制:

  • 使用者除了擁有 CREATE VIEW 許可權外,還具有操作中涉及的基礎表和其他檢視的相關許可權。
  • SELECT 語句不能引用系統或使用者變數。
  • SELECT 語句不能包含 FROM 子句中的子查詢。
  • SELECT 語句不能引用預處理語句引數。

檢視定義中引用的表或檢視必須存在。但是,建立完檢視後,可以刪除定義引用的表或檢視。可使用 CHECK TABLE 語句檢查檢視定義是否存在這類問題。

檢視定義中允許使用 ORDER BY 語句,但是若從特定檢視進行選擇,而該檢視使用了自己的 ORDER BY 語句,則檢視定義中的 ORDER BY 將被忽略。

檢視定義中不能引用 TEMPORARY 表(臨時表),不能建立 TEMPORARY 檢視。

WITH CHECK OPTION 的意思是,修改檢視時,檢查插入的資料是否符合 WHERE 設定的條件。

查詢檢視

檢視一經定義之後,就可以如同查詢資料表一樣,使用 SELECT 語句查詢檢視中的資料,語法和查詢基礎表的資料一樣。

檢視用於查詢主要應用在以下幾個方面:

  • 使用檢視重新格式化檢索出的資料。
  • 使用檢視簡化複雜的表連線。
  • 使用檢視過濾資料。

DESCRIBE 可以用來檢視檢視,語法如下:

DESCRIBE 檢視名;

注意:DESCRIBE 一般情況下可以簡寫成 DESC,輸入這個命令的執行結果和輸入 DESCRIBE 是一樣的。

MySQL檢視檢視

建立好檢視後,可以通過檢視檢視的語句來檢視檢視的欄位資訊以及詳細資訊。

檢視檢視的欄位資訊

檢視檢視的欄位資訊與檢視資料表的欄位資訊一樣,都是使用 DESCRIBE 關鍵字來檢視的。具體語法如下:

DESCRIBE 檢視名;

或簡寫成:

DESC 檢視名;

檢視檢視的欄位內容與檢視錶的欄位內容顯示的格式是相同的。因此,更能說明檢視實際上也是一張資料表了,不同的是,檢視中的資料都來自於資料庫中已經存在的表。

檢視檢視的詳細資訊

在 MySQL 中,SHOW CREATE VIEW 語句可以檢視檢視的詳細定義。其語法如下所示:

SHOW CREATE VIEW 檢視名;

所有檢視的定義都是儲存在 information_schema 資料庫下的 views 表中,也可以在這個表中檢視所有檢視的詳細資訊,SQL 語句如下:

SELECT * FROM information_schema.views;

不過,通常情況下都是使用 SHOW CREATE VIEW 語句。

MySQL修改檢視

修改檢視是指修改 MySQL 資料庫中存在的檢視,當基本表的某些欄位發生變化時,可以通過修改檢視來保持與基本表的一致性。

基本語法

可以使用 ALTER VIEW 語句來對已有的檢視進行修改。

語法格式如下:

ALTER VIEW <檢視名> AS <SELECT語句>

語法說明如下:

  • <檢視名>:指定檢視的名稱。該名稱在資料庫中必須是唯一的,不能與其他表或檢視同名。
  • <SELECT 語句>:指定建立檢視的 SELECT 語句,可用於查詢多個基礎表或源檢視。

需要注意的是,對於 ALTER VIEW 語句的使用,需要使用者具有針對檢視的 CREATE VIEW 和 DROP 許可權,以及由 SELECT 語句選擇的每一列上的某些許可權。

修改檢視的定義,除了可以通過 ALTER VIEW 外,也可以使用 DROP VIEW 語句先刪除檢視,再使用 CREATE VIEW 語句來實現。

修改檢視內容

檢視是一個虛擬表,實際的資料來自於基本表,所以通過插入、修改和刪除操作更新檢視中的資料,實質上是在更新檢視所引用的基本表的資料。

注意:對檢視的修改就是對基本表的修改,因此在修改時,要滿足基本表的資料定義。

某些檢視是可更新的。也就是說,可以使用 UPDATE、DELETE 或 INSERT 等語句更新基本表的內容。對於可更新的檢視,檢視中的行和基本表的行之間必須具有一對一的關係。

還有一些特定的其他結構,這些結構會使得檢視不可更新。更具體地講,如果檢視包含以下結構中的任何一種,它就是不可更新的:

  • 聚合函式 SUM()、MIN()、MAX()、COUNT() 等。
  • DISTINCT 關鍵字。
  • GROUP BY 子句。
  • HAVING 子句。
  • UNION 或 UNION ALL 運算子。
  • 位於選擇列表中的子查詢。
  • FROM 子句中的不可更新檢視或包含多個表。
  • WHERE 子句中的子查詢,引用 FROM 子句中的表。
  • ALGORITHM 選項為 TEMPTABLE(使用臨時表總會使檢視成為不可更新的)的時候。

MySQL刪除檢視

刪除檢視是指刪除 MySQL 資料庫中已存在的檢視。刪除檢視時,只能刪除檢視的定義,不會刪除資料。

基本語法

可以使用 DROP VIEW 語句來刪除檢視。

語法格式如下:

DROP VIEW <檢視名1> [ , <檢視名2> …]

其中:<檢視名>指定要刪除的檢視名。DROP VIEW 語句可以一次刪除多個檢視,但是必須在每個檢視上擁有 DROP 許可權。

索引是什麼

索引是一種特殊的資料庫結構,由資料表中的一列或多列組合而成,可以用來快速查詢資料表中有某一特定值的記錄

通過索引,查詢資料時不用讀完記錄的所有資訊,而只是查詢索引列。否則,資料庫系統將讀取每條記錄的所有資訊進行匹配。

可以把索引比作新華字典的音序表。例如,要查“庫”字,如果不使用音序,就需要從字典的 400 頁中逐頁來找。但是,如果提取拼音出來,構成音序表,就只需要從 10 多頁的音序表中直接查詢。這樣就可以大大節省時間。

因此,使用索引可以很大程度上提高資料庫的查詢速度,還有效的提高了資料庫系統的效能。

為什麼要使用索引

索引就是根據表中的一列或若干列按照一定順序建立的列值與記錄行之間的對應關係表,實質上是一張描述索引列的列值與原表中記錄行之間一 一對應關係的有序表。

索引是 MySQL 中十分重要的資料庫物件,是資料庫效能調優技術的基礎,常用於實現資料的快速檢索。

在 MySQL 中,通常有以下兩種方式訪問資料庫表的行資料:

順序訪問

順序訪問是在表中實行全表掃描,從頭到尾逐行遍歷,直到在無序的行資料中找到符合條件的目標資料。

順序訪問實現比較簡單,但是當表中有大量資料的時候,效率非常低下。例如,在幾千萬條資料中查詢少量的資料時,使用順序訪問方式將會遍歷所有的資料,花費大量的時間,顯然會影響資料庫的處理效能。

索引訪問

索引訪問是通過遍歷索引來直接訪問表中記錄行的方式。

使用這種方式的前提是對錶建立一個索引,在列上建立了索引之後,查詢資料時可以直接根據該列上的索引找到對應記錄行的位置,從而快捷地查詢到資料。索引儲存了指定列資料值的指標,根據指定的排序順序對這些指標排序。

  • 例如,在學生基本資訊表 tb_students 中,如果基於 student_id 建立了索引,系統就建立了一張索引列到實際記錄的對映表。當使用者需要查詢 student_id 為 12022 的資料的時候,系統先在 student_id 索引上找到該記錄,然後通過對映表直接找到資料行,並且返回該行資料。因為掃描索引的速度一般遠遠大於掃描實際資料行的速度,所以採用索引的方式可以大大提高資料庫的工作效率。

簡而言之,不使用索引,MySQL 就必須從第一條記錄開始讀完整個表,直到找出相關的行。表越大,查詢資料所花費的時間就越多。如果表中查詢的列有一個索引,MySQL 就能快速到達一個位置去搜尋資料檔案,而不必檢視所有資料,這樣將會節省很大一部分時間。

索引的優缺點

索引有其明顯的優勢,也有其不可避免的缺點。

優點

索引的優點如下:

  • 通過建立唯一索引可以保證資料庫表中每一行資料的唯一性。
  • 可以給所有的 MySQL 列型別設定索引。
  • 可以大大加快資料的查詢速度,這是使用索引最主要的原因。
  • 在實現資料的參考完整性方面可以加速表與表之間的連線。
  • 在使用分組和排序子句進行資料查詢時也可以顯著減少查詢中分組和排序的時間

缺點

增加索引也有許多不利的方面,主要如下:

  • 建立和維護索引組要耗費時間,並且隨著資料量的增加所耗費的時間也會增加。
  • 索引需要佔磁碟空間,除了資料表佔資料空間以外,每一個索引還要佔一定的物理空間。如果有大量的索引,索引檔案可能比資料檔案更快達到最大檔案尺寸。
  • 當對錶中的資料進行增加、刪除和修改的時候,索引也要動態維護,這樣就降低了資料的維護速度。

使用索引時,需要綜合考慮索引的優點和缺點。

索引可以提高查詢速度,但是會影響插入記錄的速度。因為,向有索引的表中插入記錄時,資料庫系統會按照索引進行排序,這樣就降低了插入記錄的速度,插入大量記錄時的速度影響會更加明顯。

MySQL索引型別詳解

索引的型別和儲存引擎有關,每種儲存引擎所支援的索引型別不一定完全相同。MySQL 索引可以從儲存方式、邏輯角度和實際使用的角度來進行分類。

儲存方式區分

根據儲存方式的不同,MySQL 中常用的索引在物理上分為 B-樹索引和 HASH 索引兩類,兩種不同型別的索引各有其不同的適用範圍。

B-樹索引

B-樹索引又稱為 BTREE 索引,目前大部分的索引都是採用 B-樹索引來儲存的。

B-樹索引是一個典型的資料結構,其包含的元件主要有以下幾個:

  • 葉子節點:包含的條目直接指向表裡的資料行。葉子節點之間彼此相連,一個葉子節點有一個指向下一個葉子節點的指標。
  • 分支節點:包含的條目指向索引裡其他的分支節點或者葉子節點。
  • 根節點:一個 B-樹索引只有一個根節點,實際上就是位於樹的最頂端的分支節點。

基於這種樹形資料結構,表中的每一行都會在索引上有一個對應值。因此,在表中進行資料查詢時,可以根據索引值一步一步定位到資料所在的行。

B-樹索引可以進行全鍵值、鍵值範圍和鍵值字首查詢,也可以對查詢結果進行 ORDER BY 排序。但 B-樹索引必須遵循左邊字首原則,要考慮以下幾點約束:

  • 查詢必須從索引的最左邊的列開始。
  • 查詢不能跳過某一索引列,必須按照從左到右的順序進行匹配。
  • 儲存引擎不能使用索引中範圍條件右邊的列。

雜湊索引

雜湊(Hash)一般翻譯為“雜湊”,也有直接音譯成“雜湊”的,就是把任意長度的輸入(又叫作預對映,pre-image)通過雜湊演算法變換成固定長度的輸出,該輸出就是雜湊值。

雜湊索引也稱為雜湊索引或 HASH 索引。MySQL 目前僅有 MEMORY 儲存引擎和 HEAP 儲存引擎支援這類索引。其中,MEMORY 儲存引擎可以支援 B-樹索引和 HASH 索引,且將 HASH 當成預設索引。

HASH 索引不是基於樹形的資料結構查詢資料,而是根據索引列對應的雜湊值的方法獲取表的記錄行。雜湊索引的最大特點是訪問速度快,但也存在下面的一些缺點:

  • MySQL 需要讀取表中索引列的值來參與雜湊計算,雜湊計算是一個比較耗時的操作。也就是說,相對於 B-樹索引來說,建立雜湊索引會耗費更多的時間。
  • 不能使用 HASH 索引排序。
  • HASH 索引只支援等值比較,如“=”“IN()”或“<=>”。
  • HASH 索引不支援鍵的部分匹配,因為在計算 HASH 值的時候是通過整個索引值來計算的。

邏輯區分

根據索引的具體用途,MySQL 中的索引在邏輯上分為以下 5 類:

普通索引

普通索引是 MySQL 中最基本的索引型別,它沒有任何限制,唯一任務就是加快系統對資料的訪問速度。

普通索引允許在定義索引的列中插入重複值和空值。

建立普通索引時,通常使用的關鍵字是 INDEX 或 KEY。

唯一索引

唯一索引與普通索引類似,不同的是建立唯一性索引的目的不是為了提高訪問速度,而是為了避免資料出現重複。

唯一索引列的值必須唯一,允許有空值。如果是組合索引,則列值的組合必須唯一。

建立唯一索引通常使用 UNIQUE 關鍵字。

主鍵索引

顧名思義,主鍵索引就是專門為主鍵欄位建立的索引,也屬於索引的一種。

主鍵索引是一種特殊的唯一索引,不允許值重複或者值為空。

建立主鍵索引通常使用 PRIMARY KEY 關鍵字。不能使用 CREATE INDEX 語句建立主鍵索引。

空間索引

空間索引是對空間資料型別的欄位建立的索引,使用 SPATIAL 關鍵字進行擴充套件。

建立空間索引的列必須將其宣告為 NOT NULL,空間索引只能在儲存引擎為 MyISAM 的表中建立。

空間索引主要用於地理空間資料型別 GEOMETRY。對於初學者來說,這類索引很少會用到。

全文索引

全文索引主要用來查詢文字中的關鍵字,只能在 CHAR、VARCHAR 或 TEXT 型別的列上建立。在 MySQL 中只有 MyISAM 儲存引擎支援全文索引。

全文索引允許在索引列中插入重複值和空值。

不過對於大容量的資料表,生成全文索引非常消耗時間和硬碟空間。

建立全文索引使用 FULLTEXT 關鍵字。

實際使用區分

索引在邏輯上分為以上 5 類,但在實際使用中,索引通常被建立成單列索引和組合索引。

單列索引

單列索引就是索引只包含原表的一個列。在表中的單個欄位上建立索引,單列索引只根據該欄位進行索引。

單列索引可以是普通索引,也可以是唯一性索引,還可以是全文索引。只要保證該索引只對應一個欄位即可。

多列索引

組合索引也稱為複合索引或多列索引。相對於單列索引來說,組合索引是將原表的多個列共同組成一個索引。多列索引是在表的多個欄位上建立一個索引。該索引指向建立時對應的多個欄位,可以通過這幾個欄位進行查詢。但是,只有查詢條件中使用了這些欄位中第一個欄位時,索引才會被使用。

提示:一個表可以有多個單列索引,但這些索引不是組合索引。一個組合索引實質上為表的查詢提供了多個索引,以此來加快查詢速度。

  • 比如,在一個表中建立了一個組合索引(c1,c2,c3),在實際查詢中,系統用來實際加速的索引有三個:單個索引(c1)、雙列索引(c1,c2)和多列索引(c1,c2,c3)。

MySQL建立索引

建立索引是指在某個表的一列或多列上建立一個索引,可以提高對錶的訪問速度。建立索引對 MySQL資料庫的高效執行來說是很重要的。

基本語法

MySQL 提供了三種建立索引的方法:

使用 CREATE INDEX 語句

可以使用專門用於建立索引的 CREATE INDEX 語句在一個已有的表上建立索引,但該語句不能建立主鍵。

語法格式:

CREATE <索引名> ON <表名> (<列名> [<長度>] [ ASC | DESC])

語法說明如下:

  • <索引名>:指定索引名。一個表可以建立多個索引,但每個索引在該表中的名稱是唯一的。
  • <表名>:指定要建立索引的表名。
  • <列名>:指定要建立索引的列名。通常可以考慮將查詢語句中在 JOIN 子句和 WHERE 子句裡經常出現的列作為索引列。
  • <長度>:可選項。指定使用列前的 length 個字元來建立索引。使用列的一部分建立索引有利於減小索引檔案的大小,節省索引列所佔的空間。在某些情況下,只能對列的字首進行索引。索引列的長度有一個最大上限 255 個位元組(MyISAM 和 InnoDB 表的最大上限為 1000 個位元組),如果索引列的長度超過了這個上限,就只能用列的字首進行索引。另外,BLOB 或 TEXT 型別的列也必須使用字首索引。
  • ASC|DESC:可選項。ASC指定索引按照升序來排列,DESC指定索引按照降序來排列,預設為ASC

使用 CREATE TABLE 語句

索引也可以在建立表(CREATE TABLE)的同時建立。在 CREATE TABLE 語句中新增以下語句。語法格式:

CONSTRAINT PRIMARY KEY [索引型別] (<列名>,…)

在 CREATE TABLE 語句中新增此語句,表示在建立新表的同時建立該表的主鍵。

語法格式:

KEY | INDEX [<索引名>] [<索引型別>] (<列名>,…)

在 CREATE TABLE 語句中新增此語句,表示在建立新表的同時建立該表的索引。

語法格式:

UNIQUE [ INDEX | KEY] [<索引名>] [<索引型別>] (<列名>,…)

在 CREATE TABLE 語句中新增此語句,表示在建立新表的同時建立該表的唯一性索引。

語法格式:

FOREIGN KEY <索引名> <列名>

在 CREATE TABLE 語句中新增此語句,表示在建立新表的同時建立該表的外來鍵。

在使用 CREATE TABLE 語句定義列選項的時候,可以通過直接在某個列定義後面新增 PRIMARY KEY 的方式建立主鍵。而當主鍵是由多個列組成的多列索引時,則不能使用這種方法,只能用在語句的最後加上一個 PRIMARY KRY(<列名>,…) 子句的方式來實現。

使用 ALTER TABLE 語句

CREATE INDEX 語句可以在一個已有的表上建立索引,ALTER TABLE 語句也可以在一個已有的表上建立索引。在使用 ALTER TABLE 語句修改表的同時,可以向已有的表新增索引。具體的做法是在 ALTER TABLE 語句中新增以下語法成分的某一項或幾項。

語法格式:

ADD INDEX [<索引名>] [<索引型別>] (<列名>,…)

在 ALTER TABLE 語句中新增此語法成分,表示在修改表的同時為該表新增索引。

語法格式:

ADD PRIMARY KEY [<索引型別>] (<列名>,…)

在 ALTER TABLE 語句中新增此語法成分,表示在修改表的同時為該表新增主鍵。

語法格式:

ADD UNIQUE [ INDEX | KEY] [<索引名>] [<索引型別>] (<列名>,…)

在 ALTER TABLE 語句中新增此語法成分,表示在修改表的同時為該表新增唯一性索引。

語法格式:

ADD FOREIGN KEY [<索引名>] (<列名>,…)

在 ALTER TABLE 語句中新增此語法成分,表示在修改表的同時為該表新增外來鍵。

建立普通索引

建立普通索引時,通常使用 INDEX 關鍵字。

例子:建立一個表 tb_stu_info,在該表的 height 欄位建立普通索引。輸入的 SQL 語句和執行過程如下所示。

mysql> CREATE TABLE tb_stu_info
    -> (
    -> id INT NOT NULL,
    -> name CHAR(45) DEFAULT NULL,
    -> dept_id INT DEFAULT NULL,
    -> age INT DEFAULT NULL,
    -> height INT DEFAULT NULL,
    -> INDEX(height)
    -> );
Query OK,0 rows affected (0.40 sec)
mysql> SHOW CREATE TABLE tb_stu_info\G
*************************** 1. row ***************************
       Table: tb_stu_info
Create Table: CREATE TABLE `tb_stu_info` (
  `id` int(11) NOT NULL,
  `name` char(45) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.01 sec)

建立唯一索引

建立唯一索引,通常使用 UNIQUE 引數。

例子:建立一個表 tb_stu_info2,在該表的 id 欄位上使用 UNIQUE 關鍵字建立唯一索引。輸入的 SQL 語句和執行過程如下所示。

mysql> CREATE TABLE tb_stu_info2
    -> (
    -> id INT NOT NULL,
    -> name CHAR(45) DEFAULT NULL,
    -> dept_id INT DEFAULT NULL,
    -> age INT DEFAULT NULL,
    -> height INT DEFAULT NULL,
    -> UNIQUE INDEX(height)
    -> );
Query OK,0 rows affected (0.40 sec)
mysql> SHOW CREATE TABLE tb_stu_info2\G
*************************** 1. row ***************************
       Table: tb_stu_info2
Create Table: CREATE TABLE `tb_stu_info2` (
  `id` int(11) NOT NULL,
  `name` char(45) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  UNIQUE KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)

MySQL檢視索引

索引建立完成後,可以利用 SQL 語句檢視已經存在的索引。在 MySQL 中,可以使用 SHOW INDEX 語句檢視錶中建立的索引。

檢視索引的語法格式如下:

SHOW INDEX FROM <表名> [ FROM <資料庫名>]

語法說明如下:

  • <表名>:指定需要檢視索引的資料表名。
  • <資料庫名>:指定需要檢視索引的資料表所在的資料庫,可省略。比如,SHOW INDEX FROM student FROM test; 語句表示檢視 test 資料庫中 student 資料表的索引。

其中各主要引數說明如下:

引數 說明
Table 表示建立索引的資料表名,這裡是 tb_stu_info2 資料表。
Non_unique 表示該索引是否是唯一索引。若不是唯一索引,則該列的值為 1;若是唯一索引,則該列的值為 0。
Key_name 表示索引的名稱。
Seq_in_index 表示該列在索引中的位置,如果索引是單列的,則該列的值為 1;如果索引是組合索引,則該列的值為每列在索引定義中的順序。
Column_name 表示定義索引的列欄位。
Collation 表示列以何種順序儲存在索引中。在 MySQL 中,升序顯示值“A”(升序),若顯示為 NULL,則表示無分類。
Cardinality 索引中唯一值數目的估計值。基數根據被儲存為整數的統計資料計數,所以即使對於小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL 使用該索引的機會就越大。
Sub_part 表示列中被編入索引的字元的數量。若列只是部分被編入索引,則該列的值為被編入索引的字元的數目;若整列被編入索引,則該列的值為 NULL。
Packed 指示關鍵字如何被壓縮。若沒有被壓縮,值為 NULL。
Null 用於顯示索引列中是否包含 NULL。若列含有 NULL,該列的值為 YES。若沒有,則該列的值為 NO。
Index_type 顯示索引使用的型別和方法(BTREE、FULLTEXT、HASH、RTREE)。
Comment 顯示評註。

MySQL修改和刪除索引

刪除索引是指將表中已經存在的索引刪除掉。不用的索引建議進行刪除,因為它們會降低表的更新速度,影響資料庫的效能。對於這樣的索引,應該將其刪除。

在 MySQL 中修改索引可以通過刪除原索引,再根據需要建立一個同名的索引,從而實現修改索引的操作。

基本語法

當不再需要索引時,可以使用 DROP INDEX 語句或 ALTER TABLE 語句來對索引進行刪除。

使用 DROP INDEX 語句

語法格式:

DROP INDEX <索引名> ON <表名>

語法說明如下:

  • <索引名>:要刪除的索引名。
  • <表名>:指定該索引所在的表名。

使用 ALTER TABLE 語句

根據 ALTER TABLE 語句的語法可知,該語句也可以用於刪除索引。具體使用方法是將 ALTER TABLE 語句的語法中部分指定為以下子句中的某一項。

  • DROP PRIMARY KEY:表示刪除表中的主鍵。一個表只有一個主鍵,主鍵也是一個索引。
  • DROP INDEX index_name:表示刪除名稱為 index_name 的索引。
  • DROP FOREIGN KEY fk_symbol:表示刪除外來鍵。

注意:如果刪除的列是索引的組成部分,那麼在刪除該列時,也會將該列從索引中刪除;如果組成索引的所有列都被刪除,那麼整個索引將被刪除。

索引失效

索引可以提高查詢的速度,但並不是使用帶有索引的欄位查詢時,索引都會起作用。使用索引有幾種特殊情況,在這些情況下,有可能使用帶有索引的欄位查詢時,索引並沒有起作用,下面重點介紹這幾種特殊情況。

  1. 查詢語句中使用LIKE關鍵字:在查詢語句中使用 LIKE 關鍵字進行查詢時,如果匹配字串的第一個字元為“%”,索引不會被使用。如果“%”不是在第一個位置,索引就會被使用。
  2. 查詢語句中使用多列索引:多列索引是在表的多個欄位上建立一個索引,只有查詢條件中使用了這些欄位中的第一個欄位,索引才會被使用。
  3. 查詢語句中使用OR關鍵字:查詢語句只有 OR 關鍵字時,如果 OR 前後的兩個條件的列都是索引,那麼查詢中將使用索引。如果 OR 前後有一個條件的列不是索引,那麼查詢中將不使用索引。

MySQL索引的設計原則

索引的設計可以遵循一些已有的原則,建立索引的時候應儘量考慮符合這些原則,便於提升索引的使用效率,更高效的使用索引。

  1. 選擇唯一性索引:唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄。
    • 例如,學生表中學號是具有唯一性的欄位。為該欄位建立唯一性索引可以很快的確定某個學生的資訊。如果使用姓名的話,可能存在同名現象,從而降低查詢速度。
  2. 為經常需要排序、分組和聯合操作的欄位建立索引:經常需要 ORDER BY、GROUP BY、DISTINCT 和 UNION 等操作的欄位,排序操作會浪費很多時間。如果為其建立索引,可以有效地避免排序操作。
  3. 為常作為查詢條件的欄位建立索引:如果某個欄位經常用來做查詢條件,那麼該欄位的查詢速度會影響整個表的查詢速度。因此,為這樣的欄位建立索引,可以提高整個表的查詢速度。
    • 注意:常查詢條件的欄位不一定是所要選擇的列,換句話說,最適合索引的列是出現在 WHERE 子句中的列,或連線子句中指定的列,而不是出現在 SELECT 關鍵字後的選擇列表中的列。
  4. 限制索引的數目:索引的數目不是“越多越好”。每個索引都需要佔用磁碟空間,索引越多,需要的磁碟空間就越大。在修改表的內容時,索引必須進行更新,有時還可能需要重構。因此,索引越多,更新表的時間就越長。
    • 如果有一個索引很少利用或從不使用,那麼會不必要地減緩表的修改速度。此外,MySQL 在生成一個執行計劃時,要考慮各個索引,這也要花費時間。建立多餘的索引給查詢優化帶來了更多的工作。索引太多,也可能會使 MySQL 選擇不到所要使用的最佳索引。
  5. 儘量使用資料量少的索引:如果索引的值很長,那麼查詢的速度會受到影響。
    • 例如,對一個 CHAR(100) 型別的欄位進行全文檢索需要的時間肯定要比對 CHAR(10) 型別的欄位需要的時間要多。
  6. 資料量小的表最好不要使用索引:由於資料較小,查詢花費的時間可能比遍歷索引的時間還要短,索引可能不會產生優化效果。
  7. 儘量使用字首來索引:如果索引欄位的值很長,最好使用值的字首來索引。
    • 例如,TEXT 和 BLOG 型別的欄位,進行全文檢索會很浪費時間。如果只檢索欄位的前面的若干個字元,這樣可以提高檢索速度。
  8. 刪除不再使用或者很少使用的索引:表中的資料被大量更新,或者資料的使用方式被改變後,原有的一些索引可能不再需要。應該定期找出這些索引,將它們刪除,從而減少索引對更新操作的影響。

總結:選擇索引的最終目的是為了使查詢的速度變快,上面給出的原則是最基本的準則,但不能只拘泥於上面的準則。應該在學習和工作中不斷的實踐,根據應用的實際情況進行分析和判斷,選擇最合適的索引方式。

儲存過程是什麼

在資料庫的實際操作中,經常會有需要多條 SQL 語句處理多個表才能完成的操作。

  • 例如,為了確認學生能否畢業,需要同時查詢學生檔案表、成績表和綜合表,此時就需要使用多條 SQL 語句來針對這幾個資料表完成處理要求。

儲存過程是一組為了完成特定功能的 SQL 語句集合。使用儲存過程的目的是將常用或複雜的工作預先用 SQL 語句寫好並用一個指定名稱儲存起來,這個過程經編譯和優化後儲存在資料庫伺服器中,因此稱為儲存過程。當以後需要資料庫提供與已定義好的儲存過程的功能相同的服務時,只需呼叫“CALL儲存過程名字”即可自動完成。

常用運算元據庫的 SQL 語句在執行的時候需要先編譯,然後執行。儲存過程則採用另一種方式來執行 SQL 語句。

一個儲存過程是一個可程式設計的函式,它在資料庫中建立並儲存,一般由 SQL 語句和一些特殊的控制結構組成。當希望在不同的應用程式或平臺上執行相同的特定功能時,儲存過程尤為合適。

MySQL 5.0 版本以前並不支援儲存過程,這使 MySQL 在應用上大打折扣。MySQL 從 5.0 版本開始支援儲存過程,既提高了資料庫的處理速度,同時也提高了資料庫程式設計的靈活性

儲存過程是資料庫中的一個重要功能,儲存過程可以用來轉換資料、資料遷移、製作報表,它類似於程式語言,一次執行成功,就可以隨時被呼叫,完成指定的功能操作。

使用儲存過程不僅可以提高資料庫的訪問效率,同時也可以提高資料庫使用的安全性。

對於呼叫者來說,儲存過程封裝了 SQL 語句,呼叫者無需考慮邏輯功能的具體實現過程。只是簡單呼叫即可,它可以被 Java 和 C# 等程式語言呼叫。

編寫儲存過程對開發者要求稍微高一些,但這並不影響儲存過程的普遍使用,因為儲存過程有如下優點:

  1. 封裝性:通常完成一個邏輯功能需要多條 SQL 語句,而且各個語句之間很可能傳遞引數,所以,編寫邏輯功能相對來說稍微複雜些,而儲存過程可以把這些 SQL 語句包含到一個獨立的單元中,使外界看不到複雜的 SQL 語句,只需要簡單呼叫即可達到目的。並且資料庫專業人員可以隨時對儲存過程進行修改,而不會影響到呼叫它的應用程式原始碼。
  2. 可增強 SQL 語句的功能和靈活性:儲存過程可以用流程控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。
  3. 可減少網路流量:由於儲存過程是在伺服器端執行的,且執行速度快,因此當客戶計算機上呼叫該儲存過程時,網路中傳送的只是該呼叫語句,從而可降低網路負載。
  4. 高效能:當儲存過程被成功編譯後,就儲存在資料庫伺服器裡了,以後客戶端可以直接呼叫,這樣所有的 SQL 語句將從伺服器執行,從而提高效能。但需要說明的是,儲存過程不是越多越好,過多的使用儲存過程反而影響系統效能。
  5. 提高資料庫的安全性和資料的完整性:儲存過程提高安全性的一個方案就是把它作為中間元件,儲存過程裡可以對某些表做相關操作,然後儲存過程作為介面提供給外部程式。這樣,外部程式無法直接運算元據庫表,只能通過儲存過程來操作對應的表,因此在一定程度上,安全性是可以得到提高的。
  6. 使資料獨立:資料的獨立可以達到解耦的效果,也就是說,程式可以呼叫儲存過程,來替代執行多條的 SQL 語句。這種情況下,儲存過程把資料同使用者隔離開來,優點就是當資料表的結構改變時,呼叫表不用修改程式,只需要資料庫管理者重新編寫儲存過程即可。

MySQL建立儲存過程

MySQL 儲存過程是一些 SQL 語句的集合,比如有時候我們可能需要一大串的 SQL 語句,或者說在編寫 SQL 語句的過程中需要設定一些變數的值,這個時候我們就完全有必要編寫一個儲存過程。

編寫儲存過程並不是件簡單的事情,但是使用儲存過程可以簡化操作,且減少冗餘的操作步驟,同時,還可以減少操作過程中的失誤,提高效率,因此應該儘可能的學會使用儲存過程。

下面主要介紹如何建立儲存過程。

可以使用 CREATE PROCEDURE 語句建立儲存過程,語法格式如下:

CREATE PROCEDURE <過程名> ( [過程引數[,…] ] ) <過程體>
[過程引數[,…] ] 格式
[ IN | OUT | INOUT ] <引數名> <型別>

語法說明如下:

  1. 過程名:儲存過程的名稱,預設在當前資料庫中建立。若需要在特定資料庫中建立儲存過程,則要在名稱前面加上資料庫的名稱,即 db_name.sp_name。
    • 需要注意的是,名稱應當儘量避免選取與 MySQL 內建函式相同的名稱,否則會發生錯誤。
  2. 過程引數:儲存過程的引數列表。其中,<引數名>為引數名,<型別>為引數的型別(可以是任何有效的 MySQL 資料型別)。當有多個引數時,引數列表中彼此間用逗號分隔。儲存過程可以沒有引數(此時儲存過程的名稱後仍需加上一對括號),也可以有 1 個或多個引數。
    • MySQL 儲存過程支援三種型別的引數,即輸入引數、輸出引數和輸入/輸出引數,分別用 IN、OUT 和 INOUT 三個關鍵字標識。其中,輸入引數可以傳遞給一個儲存過程,輸出引數用於儲存過程需要返回一個操作結果的情形,而輸入/輸出引數既可以充當輸入引數也可以充當輸出引數。
    • 需要注意的是,引數的取名不要與資料表的列名相同,否則儘管不會返回出錯資訊,但是儲存過程的 SQL 語句會將引數名看作列名,從而引發不可預知的結果。
  3. 過程體儲存過程的主體部分,也稱為儲存過程體,包含在過程呼叫的時候必須執行的 SQL 語句。這個部分以關鍵字 BEGIN 開始,以關鍵字 END 結束。若儲存過程體中只有一條 SQL 語句,則可以省略 BEGIN-END 標誌。

DELIMITER 命令

在儲存過程的建立中,經常會用到一個十分重要的 MySQL 命令,即 DELIMITER 命令

在 MySQL 中,伺服器處理 SQL 語句預設是以分號作為語句結束標誌的。然而,在建立儲存過程時,儲存過程體可能包含有多條 SQL 語句,這些 SQL 語句如果仍以分號作為語句結束符,那麼 MySQL 伺服器在處理時會以遇到的第一條 SQL 語句結尾處的分號作為整個程式的結束符,而不再去處理儲存過程體中後面的 SQL 語句,這樣顯然不行。

為解決以上問題,通常使用 DELIMITER 命令將結束命令修改為其他字元。語法格式如下:

DELIMITER $$

語法說明如下:

  • $$ 是使用者定義的結束符,通常這個符號可以是一些特殊的符號,如兩個“?”或兩個“¥”等。
  • 當使用 DELIMITER 命令時,應該避免使用反斜槓“\”字元,因為它是 MySQL 的轉義字元。

在 MySQL 命令列客戶端輸入如下 SQL 語句。

mysql > DELIMITER ??

成功執行這條 SQL 語句後,任何命令、語句或程式的結束標誌就換為兩個問號“??”了。

若希望換回預設的分號“;”作為結束標誌,則在 MySQL 命令列客戶端輸入下列語句即可:

mysql > DELIMITER ;

注意:DELIMITER 和分號“;”之間一定要有一個空格。在建立儲存過程時,必須具有 CREATE ROUTINE 許可權。

MySQL檢視儲存過程

建立好儲存過程後,使用者可以通過 SHOW ATATUS 語句來檢視儲存過程的狀態,也可以通過 SHOW CREATE 語句來檢視儲存過程的定義。

檢視儲存過程的狀態

MySQL 中可以通過 SHOW STATUS 語句檢視儲存過程的狀態,其基本語法形式如下:

SHOW PROCEDURE STATUS LIKE 儲存過程名;

LIKE 儲存過程名用來匹配儲存過程的名稱,LIKE 不能省略。

檢視儲存過程的定義

MySQL 中可以通過 SHOW CREATE 語句檢視儲存過程的狀態,語法格式如下:

SHOW CREATE PROCEDURE 儲存過程名;

SHOW STATUS 語句只能檢視儲存過程是操作的哪一個資料庫、儲存過程的名稱、型別、誰定義的、建立和修改時間、字元編碼等資訊。但是,這個語句不能查詢儲存過程的集體定義,如果需要檢視詳細定義,需要使用 SHOW CREATE 語句。

儲存過程的資訊都儲存在 information_schema 資料庫下的 Routines 表中,可以通過查詢該表的記錄來查詢儲存過程的資訊,SQL 語句如下:

SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=儲存過程名;

在 information_schema 資料庫下的 routines 表中,儲存著所有儲存過程的定義。所以,使用 SELECT 語句查詢 routines 表中的儲存過程和函式的定義時,一定要使用 routine_name 欄位指定儲存過程的名稱,否則,將查詢出所有的儲存過程的定義。

MySQL修改儲存過程

在實際開發過程中,業務需求修改的情況時有發生,所以修改 MySQL 中的儲存過程是不可避免的。

MySQL 中通過 ALTER PROCEDURE 語句來修改儲存過程

MySQL 中修改儲存過程的語法格式如下:

ALTER PROCEDURE 儲存過程名 [ 特徵 ... ]

特徵指定了儲存過程的特性,可能的取值有:

  • CONTAINS SQL 表示子程式包含 SQL 語句,但不包含讀或寫資料的語句。
  • NO SQL 表示子程式中不包含 SQL 語句。
  • READS SQL DATA 表示子程式中包含讀資料的語句。
  • MODIFIES SQL DATA 表示子程式中包含寫資料的語句。
  • SQL SECURITY { DEFINER |INVOKER } 指明誰有許可權來執行。
  • DEFINER 表示只有定義者自己才能夠執行。
  • INVOKER 表示呼叫者可以執行。
  • COMMENT 'string' 表示註釋資訊。

注意:ALTER PROCEDURE 語句用於修改儲存過程的某些特徵。如果要修改儲存過程的內容,可以先刪除原儲存過程,再以相同的命名建立新的儲存過程;如果要修改儲存過程的名稱,可以先刪除原儲存過程,再以不同的命名建立新的儲存過程。

MySQL刪除儲存過程

儲存過程被建立後,就會一直儲存在資料庫伺服器上,直至被刪除。當 MySQL 資料庫中存在廢棄的儲存過程時,我們需要將它從資料庫中刪除。

MySQL 中使用 DROP PROCEDURE 語句來刪除資料庫中已經存在的儲存過程。語法格式如下:

DROP PROCEDURE [ IF EXISTS ] <過程名>

語法說明如下:

  • 過程名:指定要刪除的儲存過程的名稱。
  • IF EXISTS:指定這個關鍵字,用於防止因刪除不存在的儲存過程而引發的錯誤。

注意:儲存過程名稱後面沒有引數列表,也沒有括號,在刪除之前,必須確認該儲存過程沒有任何依賴關係,否則會導致其他與之關聯的儲存過程無法執行。

觸發器是什麼

MySQL 的觸發器和儲存過程一樣,都是嵌入到 MySQL 中的一段程式,是 MySQL 中管理資料的有力工具。不同的是執行儲存過程要使用 CALL 語句來呼叫,而觸發器的執行不需要使用 CALL 語句來呼叫,也不需要手工啟動,而是通過對資料表的相關操作來觸發、啟用從而實現執行。比如當對 student 表進行操作(INSERT,DELETE 或 UPDATE)時就會啟用它執行。

觸發器與資料表關係密切,主要用於保護表中的資料。特別是當有多個表具有一定的相互聯絡的時候,觸發器能夠讓不同的表保持資料的一致性。

在 MySQL 中,只有執行 INSERT、UPDATE 和 DELETE 操作時才能啟用觸發器,其它 SQL 語句則不會啟用觸發器。

那麼為什麼要使用觸發器呢?比如,在實際開發專案時,我們經常會遇到以下情況:

  • 在學生表中新增一條關於學生的記錄時,學生的總數就必須同時改變。
  • 增加一條學生記錄時,需要檢查年齡是否符合範圍要求。
  • 刪除一條學生資訊時,需要刪除其成績表上的對應記錄。
  • 刪除一條資料時,需要在資料庫存檔表中保留一個備份副本。

雖然上述情況實現的業務邏輯不同,但是它們都需要在資料表發生更改時,自動進行一些處理。這時就可以使用觸發器處理。

  • 例如,對於第一種情況,可以建立一個觸發器物件,每當新增一條學生記錄時,就執行一次計算學生總數的操作,這樣就可以保證每次新增一條學生記錄後,學生總數和學生記錄數是一致的。

觸發器的優缺點

觸發器的優點如下:

  • 觸發器的執行是自動的,當對觸發器相關表的資料做出相應的修改後立即執行。
  • 觸發器可以實施比 FOREIGN KEY 約束、CHECK 約束更為複雜的檢查和操作。
  • 觸發器可以實現表資料的級聯更改,在一定程度上保證了資料的完整性。

觸發器的缺點如下:

  • 使用觸發器實現的業務邏輯在出現問題時很難進行定位,特別是涉及到多個觸發器的情況下,會使後期維護變得困難。
  • 大量使用觸發器容易導致程式碼結構被打亂,增加了程式的複雜性,
  • 如果需要變動的資料量較大時,觸發器的執行效率會非常低。

MySQL 支援的觸發器

在實際使用中,MySQL 所支援的觸發器有三種:INSERT 觸發器、UPDATE 觸發器和 DELETE 觸發器。

INSERT 觸發器

在 INSERT 語句執行之前或之後響應的觸發器。

使用 INSERT 觸發器需要注意以下幾點:

  • 在 INSERT 觸發器程式碼內,可引用一個名為 NEW(不區分大小寫)的虛擬表來訪問被插入的行。
  • 在 BEFORE INSERT 觸發器中,NEW 中的值也可以被更新,即允許更改被插入的值(只要具有對應的操作許可權)。
  • 對於 AUTO_INCREMENT 列,NEW 在 INSERT 執行之前包含的值是 0,在 INSERT 執行之後將包含新的自動生成值。

UPDATE 觸發器

在 UPDATE 語句執行之前或之後響應的觸發器。

使用 UPDATE 觸發器需要注意以下幾點:

  • 在 UPDATE 觸發器程式碼內,可引用一個名為 NEW(不區分大小寫)的虛擬表來訪問更新的值。
  • 在 UPDATE 觸發器程式碼內,可引用一個名為 OLD(不區分大小寫)的虛擬表來訪問 UPDATE 語句執行前的值。
  • 在 BEFORE UPDATE 觸發器中,NEW 中的值可能也被更新,即允許更改將要用於 UPDATE 語句中的值(只要具有對應的操作許可權)。
  • OLD 中的值全部是隻讀的,不能被更新。

注意:當觸發器設計對觸發表自身的更新操作時,只能使用 BEFORE 型別的觸發器,AFTER 型別的觸發器將不被允許。

DELETE 觸發器

在 DELETE 語句執行之前或之後響應的觸發器。

使用 DELETE 觸發器需要注意以下幾點:

  • 在 DELETE 觸發器程式碼內,可以引用一個名為 OLD(不區分大小寫)的虛擬表來訪問被刪除的行。
  • OLD 中的值全部是隻讀的,不能被更新。

總體來說,觸發器使用的過程中,MySQL 會按照以下方式來處理錯誤。

對於事務性表,如果觸發程式失敗,以及由此導致的整個語句失敗,那麼該語句所執行的所有更改將回滾;對於非事務性表,則不能執行此類回滾,即使語句失敗,失敗之前所做的任何更改依然有效。

若 BEFORE 觸發程式失敗,則 MySQL 將不執行相應行上的操作。

若在 BEFORE 或 AFTER 觸發程式的執行過程中出現錯誤,則將導致呼叫觸發程式的整個語句失敗。

僅當 BEFORE 觸發程式和行操作均已被成功執行,MySQL 才會執行 AFTER 觸發程式。

MySQL建立觸發器

觸發器是與 MySQL 資料表有關的資料庫物件,在滿足定義條件時觸發,並執行觸發器中定義的語句集合。觸發器的這種特性可以協助應用在資料庫端確保資料的完整性。

基本語法

在 MySQL 5.7 中,可以使用 CREATE TRIGGER 語句建立觸發器。

語法格式如下:

CREATE <觸發器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<觸發器主體>

語法說明如下。

  1. 觸發器名:觸發器的名稱,觸發器在當前資料庫中必須具有唯一的名稱。如果要在某個特定資料庫中建立,名稱前面應該加上資料庫的名稱。
  2. INSERT | UPDATE | DELETE:觸發事件,用於指定啟用觸發器的語句的種類。
    • 注意:三種觸發器的執行時間如下。
      • INSERT:將新行插入表時啟用觸發器。例如,INSERT 的 BEFORE 觸發器不僅能被 MySQL 的 INSERT 語句啟用,也能被 LOAD DATA 語句啟用。
      • DELETE: 從表中刪除某一行資料時啟用觸發器,例如 DELETE 和 REPLACE 語句。
      • UPDATE:更改表中某一行資料時啟用觸發器,例如 UPDATE 語句。
  3. BEFORE | AFTER:BEFORE 和 AFTER,觸發器被觸發的時刻,表示觸發器是在啟用它的語句之前或之後觸發。若希望驗證新資料是否滿足條件,則使用 BEFORE 選項;若希望在啟用觸發器的語句執行之後完成幾個或更多的改變,則通常使用 AFTER 選項。
  4. 表名:與觸發器相關聯的表名,此表必須是永久性表,不能將觸發器與臨時表或檢視關聯起來。在該表上觸發事件發生時才會啟用觸發器。同一個表不能擁有兩個具有相同觸發時刻和事件的觸發器。例如,對於一張資料表,不能同時有兩個 BEFORE UPDATE 觸發器,但可以有一個 BEFORE UPDATE 觸發器和一個 BEFORE INSERT 觸發器,或一個 BEFORE UPDATE 觸發器和一個 AFTER UPDATE 觸發器。
  5. 觸發器主體:觸發器動作主體,包含觸發器啟用時將要執行的 MySQL 語句。如果要執行多個語句,可使用 BEGIN…END 複合語句結構。
  6. FOR EACH ROW:一般是指行級觸發,對於受觸發事件影響的每一行都要啟用觸發器的動作。例如,使用 INSERT 語句向某個表中插入多行資料時,觸發器會對每一行資料的插入都執行相應的觸發器動作。

注意:每個表都支援 INSERT、UPDATE 和 DELETE 的 BEFORE 與 AFTER,因此每個表最多支援 6 個觸發器。每個表的每個事件每次只允許有一個觸發器。單一觸發器不能與多個事件或多個表關聯。

另外,在 MySQL 中,若需要檢視資料庫中已有的觸發器,則可以使用 SHOW TRIGGERS 語句。

建立 BEFORE 型別觸發器

在 test_db 資料庫中,資料表 tb_emp8 為員工資訊表,包含 id、name、deptId 和 salary 欄位,資料表 tb_emp8 的表結構如下所示。

mysql> SELECT * FROM tb_emp8;
Empty set (0.07 sec)
mysql> DESC tb_emp8;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(22) | YES  | UNI | NULL    |       |
| deptId | int(11)     | NO   | MUL | NULL    |       |
| salary | float       | YES  |     | 0       |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.05 sec)

【例項 1】建立一個名為 SumOfSalary 的觸發器,觸發的條件是向資料表 tb_emp8 中插入資料之前,對新插入的 salary 欄位值進行求和計算。輸入的 SQL 語句和執行過程如下所示。

mysql> CREATE TRIGGER SumOfSalary
    -> BEFORE INSERT ON tb_emp8
    -> FOR EACH ROW
    -> SET @sum=@sum+NEW.salary;
Query OK, 0 rows affected (0.35 sec)

觸發器 SumOfSalary 建立完成之後,向表 tb_emp8 中插入記錄時,定義的 sum 值由 0 變成了 1500,即插入值 1000 和 500 的和,如下所示。

SET @sum=0;
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO tb_emp8
    -> VALUES(1,'A',1,1000),(2,'B',1,500);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> SELECT @sum;
+------+
| @sum |
+------+
| 1500 |
+------+
1 row in set (0.03 sec)

建立 AFTER 型別觸發器

在 test_db 資料庫中,資料表 tb_emp6 和 tb_emp7 都為員工資訊表,包含 id、name、deptId 和 salary 欄位,資料表 tb_emp6 和 tb_emp7 的表結構如下所示。

mysql> SELECT * FROM tb_emp6;
Empty set (0.07 sec)
mysql> SELECT * FROM tb_emp7;
Empty set (0.03 sec)
mysql> DESC tb_emp6;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(25) | YES  |     | NULL    |       |
| deptId | int(11)     | YES  | MUL | NULL    |       |
| salary | float       | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> DESC tb_emp7;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(25) | YES  |     | NULL    |       |
| deptId | int(11)     | YES  |     | NULL    |       |
| salary | float       | YES  |     | 0       |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.04 sec)

【例項 2】建立一個名為 double_salary 的觸發器,觸發的條件是向資料表 tb_emp6 中插入資料之後,再向資料表 tb_emp7 中插入相同的資料,並且 salary 為 tb_emp6 中新插入的 salary 欄位值的 2 倍。輸入的 SQL 語句和執行過程如下所示。

mysql> CREATE TRIGGER double_salary
    -> AFTER INSERT ON tb_emp6
    -> FOR EACH ROW
    -> INSERT INTO tb_emp7
    -> VALUES (NEW.id,NEW.name,deptId,2*NEW.salary);
Query OK, 0 rows affected (0.25 sec)

觸發器 double_salary 建立完成之後,向表 tb_emp6 中插入記錄時,同時向表 tb_emp7 中插入相同的記錄,並且 salary 欄位為 tb_emp6 中 salary 欄位值的 2 倍,如下所示。

mysql> INSERT INTO tb_emp6
    -> VALUES (1,'A',1,1000),(2,'B',1,500);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> SELECT * FROM tb_emp6;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | A    |      1 |   1000 |
|  2 | B    |      1 |    500 |
+----+------+--------+--------+
3 rows in set (0.04 sec)
mysql> SELECT * FROM tb_emp7;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | A    |      1 |   2000 |
|  2 | B    |      1 |   1000 |
+----+------+--------+--------+
2 rows in set (0.06 sec)

MySQL檢視觸發器

檢視觸發器是指檢視資料庫中已經存在的觸發器的定義、狀態和語法資訊等。MySQL 中檢視觸發器的方法包括 SHOW TRIGGERS 語句和查詢 information_schema 資料庫下的 triggers 資料表等。本節將詳細介紹這兩種檢視觸發器的方法。

SHOW TRIGGERS語句檢視觸發器資訊

在 MySQL 中,可以通過 SHOW TRIGGERS 語句來檢視觸發器的基本資訊,語法格式如下:

SHOW TRIGGERS;

對以上顯示資訊的說明如下:

  • Trigger 表示觸發器的名稱,在這裡觸發器的名稱為 trigupdate;
  • Event 表示啟用觸發器的事件,這裡的觸發事件為更新操作 UPDATE;
  • Table 表示啟用觸發器的操作物件表,這裡為 account 表;
  • Statement 表示觸發器執行的操作,這裡是向 myevent 資料表中插入一條資料;
  • Timing 表示觸發器觸發的時間,這裡為更新操作之後(AFTER);
  • 還有一些其他資訊,比如觸發器的建立時間、SQL 的模式、觸發器的定義賬戶和字符集等,這裡不再一一介紹。

SHOW TRIGGERS 語句用來檢視當前建立的所有觸發器的資訊。因為該語句無法查詢指定的觸發器,所以在觸發器較少的情況下,使用該語句會很方便。如果要檢視特定觸發器的資訊或者資料庫中觸發器較多時,可以直接從 information_schema 資料庫中的 triggers 資料表中查詢。

在triggers表中檢視觸發器資訊

在 MySQL 中,所有觸發器的資訊都存在 information_schema 資料庫的 triggers 表中,可以通過查詢命令 SELECT 來檢視,具體的語法如下:

SELECT * FROM information_schema.triggers WHERE trigger_name= '觸發器名';

其中,'觸發器名'用來指定要檢視的觸發器的名稱,需要用單引號引起來。這種方式可以查詢指定的觸發器,使用起來更加方便、靈活。

示例 2

下面使用 SELECT 命令檢視 trigupdate 觸發器,SQL 語句如下:

SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME= 'trigupdate'\G

顯示資訊的說明如下:

  • TRIGGER_SCHEMA 表示觸發器所在的資料庫;
  • TRIGGER_NAME 表示觸發器的名稱;
  • EVENT_OBJECT_TABLE 表示在哪個資料表上觸發;
  • ACTION_STATEMENT 表示觸發器觸發的時候執行的具體操作;
  • ACTION_ORIENTATION 的值為 ROW,表示在每條記錄上都觸發;
  • ACTION_TIMING 表示觸發的時刻是 AFTER;
  • 還有一些其他資訊,比如觸發器的建立時間、SQL 的模式、觸發器的定義賬戶和字符集等,這裡不再一一介紹。

上述 SQL 語句也可以不指定觸發器名稱,這樣將檢視所有的觸發器,SQL 語句如下:

SELECT * FROM information_schema.triggers \G

這個語句會顯示 triggers 資料表中所有的觸發器資訊。

MySQL修改和刪除觸發器

修改觸發器可以通過刪除原觸發器,再以相同的名稱建立新的觸發器。

基本語法

與其他 MySQL 資料庫物件一樣,可以使用 DROP 語句將觸發器從資料庫中刪除。

語法格式如下:

DROP TRIGGER [ IF EXISTS ] [資料庫名] <觸發器名>

語法說明如下:

  1. 觸發器名:要刪除的觸發器名稱。
  2. 資料庫名:可選項。指定觸發器所在的資料庫的名稱。若沒有指定,則為當前預設的資料庫。
  3. 許可權:執行 DROP TRIGGER 語句需要 SUPER 許可權。
  4. IF EXISTS:可選項。避免在沒有觸發器的情況下刪除觸發器。

注意:刪除一個表的同時,也會自動刪除該表上的觸發器。另外,觸發器不能更新或覆蓋,為了修改一個觸發器,必須先刪除它,再重新建立

刪除觸發器

使用 DROP TRIGGER 語句可以刪除 MySQL 中已經定義的觸發器。

【例項】刪除 double_salary 觸發器,輸入的 SQL 語句和執行過程如下所示。

mysql> DROP TRIGGER double_salary;
Query OK, 0 rows affected (0.03 sec)

Event事件(定時任務)是什麼

在資料庫管理中,經常要週期性的執行某一命令或 SQL 語句,於是 MySQL 5.1 版本以後就提供了事件,它可以很方便的實現 MySQL 資料庫的計劃任務,定期執行指定命令,使用起來非常簡單方便。

事件(Event)也可稱為事件排程器(Event Scheduler),是用來執行定時任務的一組 SQL 集合,可以通俗理解成 MySQL 中的定時器。一個事件可呼叫一次,也可週期性的啟動。

事件可以作為定時任務排程器,取代部分原來只能用作業系統的計劃任務才能執行的工作。另外,更值得一提的是,MySQL 的事件可以實現每秒鐘執行一個任務,非常適合對實時性要求較高的環境,而作業系統的計劃任務只能精確到每分鐘一次。

事件和觸發器類似,都是在某些事情發生時啟動。當資料庫啟動一條語句的時候,觸發器就啟動了,而事件是根據排程事件來啟動的。由於他們彼此相似,所以事件也稱為臨時性觸發器。

檢視事件是否開啟

在 MySQL 中,排程器 event_scheduler 負責呼叫事件。我們可以通過以下幾種命令檢視事件是否開啟,一般情況下預設值為 OFF。SQL 命令和執行結果如下:

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+
1 row in set, 1 warning (0.02 sec)

mysql> SELECT @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| OFF               |
+-------------------+
1 row in set (0.00 sec)

mysql> SHOW PROCESSLIST;
+----+------+-----------------+------+---------+------+----------+------------------+
| Id | User | Host            | db   | Command | Time | State    | Info             |
+----+------+-----------------+------+---------+------+----------+------------------+
|  2 | root | localhost:56279 | NULL | Query   |    0 | starting | SHOW PROCESSLIST |
+----+------+-----------------+------+---------+------+----------+------------------+
1 row in set (0.01 sec)

從結果可以看出,事件沒有開啟。因為引數 event_scheduler 的值為 OFF,並且在 PROCESSLIST 中檢視不到 event_scheduler 的資訊。如果引數 event_scheduler 的值為 ON,或者在 PROCESSLIST 中顯示了 event_scheduler 的資訊,則說明事件已經開啟。

開啟事件

開啟事件主要通過以下兩種方式實現。

通過設定全域性引數修改

可以使用 SET GLOBAL 命令設定全域性變數 event_scheduler 的值,開啟或關閉事件。將 event_scheduler 引數的值設定為 ON,表示開啟事件;設定為 OFF,則關閉事件。

例如,要開啟事件可以在命令列視窗中輸入以下命令。

mysql> SET GLOBAL event_scheduler = ON ;
Query OK, 0 rows affected (0.06 sec)

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set, 1 warning (0.01 sec)

結果顯示,event_scheduler 的值為 ON,表示事件已經開啟。

通過 SET GLOBAL 命令開啟或關閉事件,MySQL 重啟服務後事件又會回到原來的狀態,如果想要始終開啟或關閉事件,可以修改 MySQL 配置檔案。

更改配置檔案

在 MySQL 配置檔案中找到 [mysqld] 選項,然後在下面新增以下程式碼開啟事件。

event_scheduler = ON

在配置檔案中新增程式碼並儲存檔案後,重啟 MySQL 服務才能生效。

通過該方法開啟或關閉事件,重啟 MySQL 服務後,不會回到原來的狀態。例如,此時重啟 MySQL 伺服器,然後檢視事件是否開啟。

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set, 1 warning (0.01 sec)

結果顯示,引數 event_scheduler 的值為 ON,表示已經開啟。

MySQL建立事件

在 MySQL 中,可以通過 CREATE EVENT 語句來建立事件,其語法格式如下:

CREATE EVENT [IF NOT EXISTS] event_name
  ON SCHEDULE schedule
  [ON COMPLETION [NOT] PRESERVE]
  [ENABLE | DISABLE | DISABLE ON SLAVE]
  [COMMENT 'comment']
  DO event_body;

從上面的語法可以看出,CRATE EVENT 語句由多個子句組成,各子句的詳細說明如下表所示。

子句 說明
DEFINER 可選 用於定義事件執行時檢查許可權的使用者
IF NOT EXISTS 可選 用於判斷要建立的事件是否存在
EVENT event_name 必選 用於指定事件名稱,event_name 的最大長度為 64 個字元 如果未指定 event_name,則預設為當前的 MySQL 使用者名稱(不區分大小寫)
ON SCHEDULE schedule 必選 用於定義執行的時間和時間間隔 schedule 表示觸發點
ON COMPLETION [NOT] PRESERVE 可選 用於定義事件是否迴圈執行,即是一次執行還是永久執行,預設為一次執行,即 NOT PRESERVE
ENABLE | DISABLE | DISABLE ON SLAVE 可選,用於指定事件的一種屬性。 其中,關鍵字 ENABLE 表示該事件是活動的,即排程器檢查事件是否必須呼叫; 關鍵字 DISABLE 表示該事件是關閉的,即事件的宣告儲存到目錄中,但是排程器不會檢查它是否應該呼叫; 關鍵字 DISABLE ON SLAVE 表示事件在從機中是關閉的。 如果不指定以上 3 個選項中的任何一個,預設為 ENABLE
COMMENT 'comment' 可選,用於定義事件的註釋
DO event_body 必選 用於指定事件啟動時所要執行的程式碼,可以是任何有效的 SQL 語句、儲存過程或者一個計劃執行的事件。 如果包含多條語句,則可以使用 BEGIN..END 複合結構

在 ON SCHEDULE 子句中,引數 schedule 的值為一個 AT 子句,用於指定事件在某個時刻發生,其語法格式如下:

AT timestamp [+ INTERVAL interval]...
  | EVERY interval
  [STARTS timestamp [+ INTERVAL interval] ...]
  [ENDS timestamp[+ INTERVAL interval]...]

引數說明如下:

  • timestamp:一般用於只執行一次,表示一個具體的時間點,後面加上一個時間間隔,表示在這個時間間隔後事件發生。
  • EVERY 子句:用於事件在指定時間區間內每隔多長時間發生一次,其中 STARTS 子句用於指定開始時間;ENDS 子句用於指定結束時間。
  • interval:一般用於週期性執行,表示一個從現在開始的時間,其值由一個數值和單位構成。例如,使用“4 WEEK”表示 4 周,使用“'1:10'HOUR_MINUTE”表示 1 小時 10 分鐘。間隔的長短用 DATE_ADD() 函式支配。

interval 引數可以是以下值:

**YEAR** | QUARTER | **MONTH** | **DAY** | **HOUR** | **MINUTE** |
  WEEK | **SECOND** | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
  DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND

一般情況下,不建議使用不標準(以上未加粗關鍵字)的時間單位。

例子:在 test 資料庫中建立一個名稱為 e_test 的事件,用於每隔 5 秒向表 tb_eventtest 中插入一條資料。

建立 tb_eventtest 表,SQL 語句和執行結果如下:

mysql> CREATE TABLE tb_eventtest(
    -> id INT(11) PRIMARY KEY AUTO_INCREMENT,
    -> user VARCHAR(20),
    -> createtime DATETIME);
Query OK, 0 rows affected (0.07 sec)

建立 e_test 事件,SQL 語句和執行結果如下:

mysql> CREATE EVENT IF NOT EXISTS e_test ON SCHEDULE EVERY 5 SECOND
    -> ON COMPLETION PRESERVE
    -> DO INSERT INTO tb_eventtest(user,createtime)VALUES('MySQL',NOW());
Query OK, 0 rows affected (0.04 sec)

建立事件後,查詢 tb_eventtest 中的資料,SQL 語句和執行結果如下:

mysql> SELECT * FROM tb_eventtest;
+----+-------+---------------------+
| id | user  | createtime          |
+----+-------+---------------------+
|  1 | MySQL | 2020-05-21 10:41:39 |
|  2 | MySQL | 2020-05-21 10:41:44 |
|  3 | MySQL | 2020-05-21 10:41:49 |
|  4 | MySQL | 2020-05-21 10:41:54 |
+----+-------+---------------------+
4 rows in set (0.01 sec)

從結果可以看出,系統每隔 5 秒插入一條資料,這說明事件建立執行成功了。

MySQL檢視事件

建立好事件後,使用者可以通過以下 3 種方式來檢視事件的狀態資訊:

  1. 檢視 mysql.event
  2. 檢視 information_schema.events
  3. 切換到相應的資料庫後執行 SHOW EVENTS;

檢視 information_schema.events 表中的事件狀態資訊。SQL 語句和執行結果如下:

mysql> SELECT * FROM information_schema.events limit 1\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: test
          EVENT_NAME: e_test
             DEFINER: root@localhost
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: INSERT INTO tb_eventtest(user,createtime)VALUES('MySQL',NOW())
          EVENT_TYPE: RECURRING
          EXECUTE_AT: NULL
      INTERVAL_VALUE: 5
      INTERVAL_FIELD: SECOND
            SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
              STARTS: 2020-05-21 10:41:39
                ENDS: NULL
              STATUS: ENABLED
       ON_COMPLETION: PRESERVE
             CREATED: 2020-05-21 10:41:39
        LAST_ALTERED: 2020-05-21 10:41:39
       LAST_EXECUTED: 2020-05-21 12:38:54
       EVENT_COMMENT:
          ORIGINATOR: 1
CHARACTER_SET_CLIENT: gbk
COLLATION_CONNECTION: gbk_chinese_ci
  DATABASE_COLLATION: utf8_unicode_ci
1 row in set (0.08 sec)

以上引數說明如下表所示:

引數名 說明
EVENT_CATALOG 事件存放目錄,一般情況下,值為 def,不建議修改
EVENT_SCHEMA 事件所在的資料庫
EVENT_NAME 事件名稱
DEFINER 事件的定義者
TIME_ZONE 事件使用的時區,預設是 SYSTEM,不建議修改
EVENT_BODY 一般情況下,值為 SQL,不建議修改
EVENT_DEFINITION 該事件的內容,可以是具體的 INSERT 等 SQL,也可以是一個呼叫的儲存過程
EVENT_TYPE 事件型別,這個引數比較重要,在定義時指定 有兩個值:RECURRING 和 ONE TIME RECURRING 表示只要符合條件就會重複執行,RECURRING 型別的事件一般為 NULL,表示該事件的預計執行時間 ONE TIME 只會呼叫 EXECUTE_AT,針對 one-time 型別的事件有效
INTERVAL_VALUE 針對 RECURRING 型別的事件有效,表示執行間隔長度
INTERVAL_FIELD 針對 RECURRING 型別的事件有效,表示執行間隔的單位,一般是 SECOND,DAY 等值,可參考建立語法
SQL_MODE 當前事件採用的 SQL_MODE
STARTS 針對 RECURRING 型別的事件有效,表示一個事件從哪個時間點開始執行,和 one-time 的 EXECUTE_AT 功能類似。 為 NULL 時表示一符合條件就開始執行
ENDS 針對 RECURRING 型別的事件有效,表示一個事件到了哪個時間點後不再執行,如果為 NULL 就是永不停止
STATUS 一般有三個值,ENABLED、DISABLED 和 SLAVESIDE_DISABLED
ON_COMPLETION 只有兩個值,PRESERVE 和 NOT PRESERVE
CREATED 事件的建立時間
LAST_ALTERED 事件最近一次被修改的時間
LAST_EXECUTED 事件最近一次執行的時間,如果為 NULL 表示從未執行過
EVENT_COMMENT 事件的註釋資訊
ORIGINATOR 當前事件建立時的 server-id,用於主從上的處理,比如 SLAVESIDE_DISABLED
CHARACTER_SET_CLIENT 事件建立時的客戶端字符集
COLLATION_CONNECTION 事件建立時的連線字元校驗規則
DATABASE_COLLATION 事件建立時的資料庫字符集校驗規則

MySQL修改和刪除事件

修改事件

在 MySQL 中,事件建立之後,可以使用 ALTER EVENT 語句修改其定義和相關屬性。

修改事件的語法格式如下:

ALTER EVENT event_name
  ON SCHEDULE schedule
  [ON COMPLETION [NOT] PRESERVE]
  [ENABLE | DISABLE | DISABLE ON SLAVE]
  [COMMENT 'comment']
  DO event_body;

ALTER EVENT 語句還有一個用法就是讓一個事件關閉或再次讓其活動。

例子:修改 e_test 事件,讓其每隔 30 秒向表 tb_eventtest 中插入一條資料,SQL 語句和執行結果如下所示:

mysql> ALTER EVENT e_test ON SCHEDULE EVERY 30 SECOND
    -> ON COMPLETION PRESERVE
    -> DO INSERT INTO tb_eventtest(user,createtime) VALUES('MySQL',NOW());
Query OK, 0 rows affected (0.04 sec)

mysql> TRUNCATE TABLE tb_eventtest;
Query OK, 0 rows affected (0.04 sec)

mysql> SELECT * FROM tb_eventtest;
+----+-------+---------------------+
| id | user  | createtime          |
+----+-------+---------------------+
|  1 | MySQL | 2020-05-21 13:23:49 |
|  2 | MySQL | 2020-05-21 13:24:19 |
+----+-------+---------------------+
2 rows in set (0.00 sec)

由結果可以看出,修改事件後,表 tb_eventtest 中的資料由原來的每 5 秒插入一條,變為每 30 秒插入一條。

使用 ALTER EVENT 語句還可以臨時關閉一個已經建立的事件。

例子:臨時關閉事件 e_test 的具體程式碼如下所示:

mysql> ALTER EVENT e_test DISABLE;
Query OK, 0 rows affected (0.00 sec)

查詢 tb_eventtest 表中的資料,SQL 語句如下:

SELECT * FROM tb_eventtest;

為了確定事件已關閉,可以查詢兩次(每次間隔 1 分鐘)tb_eventtest 表的資料,SQL 語句和執行結果如下所示:

mysql> TRUNCATE TABLE tb_eventtest;
Query OK, 0 rows affected (0.05 sec)

mysql> SELECT * FROM tb_eventtest;
Empty set (0.00 sec)

mysql> SELECT * FROM tb_eventtest;
Empty set (0.00 sec)

由結果可以看出,臨時關閉事件後,系統就不再繼續向表 tb_eventtest 中插入資料了。

刪除事件

在 MySQL 中,可以使用 DROP EVENT 語句刪除已經建立的事件。語法格式如下:

DROP EVENT [IF EXISTS] event_name;

例子:刪除事件 e_test,SQL 語句和執行結果如下:

mysql> DROP EVENT IF EXISTS e_test;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM information_schema.events \G
Empty set (0.00 sec)

儲存函式詳解

儲存函數和儲存過程一樣,都是在資料庫中定義一些 SQL 語句的集合。儲存函式可以通過 return 語句返回函式值,主要用於計算並返回一個值。而儲存過程沒有直接返回值,主要用於執行操作。

在 MySQL 中,使用 CREATE FUNCTION 語句來建立儲存函式,其語法形式如下:

CREATE FUNCTION sp_name ([func_parameter[...]])
RETURNS type
[characteristic ...] routine_body

其中:

  • sp_name 引數:表示儲存函式的名稱;
  • func_parameter:表示儲存函式的引數列表;
  • RETURNS type:指定返回值的型別;
  • characteristic 引數:指定儲存函式的特性,該引數的取值與儲存過程是一樣的;
  • routine_body 引數:表示 SQL 程式碼的內容,可以用 BEGIN...END 來標示 SQL 程式碼的開始和結束。

注意:在具體建立函式時,函式名不能與已經存在的函式名重名。除了上述要求外,推薦函式名命名(識別符號)為 function_xxx 或者 func_xxx。

func_parameter 可以由多個引數組成,其中每個引數由引數名稱和引數型別組成,其形式如下:

[IN | OUT | INOUT] param_name type;

其中:

  • IN 表示輸入引數,OUT 表示輸出引數,INOUT 表示既可以輸入也可以輸出;
  • param_name 引數是儲存函式的引數名稱;
  • type 引數指定儲存函式的引數型別,該型別可以是 MySQL 資料庫的任意資料型別。

建立函式與建立儲存過程一樣,需要通過命令 DELIMITER // 將 SQL 語句的結束符由“;”修改為“//”,最後通過命令 DELIMITER ; 將結束符號修改成 SQL 語句中預設的結束符號。

如果在儲存函式中的 RETURN 語句返回一個型別不同於函式的 RETURNS 子句中指定型別的值,返回值將被強制為恰當的型別。比如,如果一個函式返回一個 ENUM 或 SET 值,但是 RETURN 語句返回一個整數,對於 SET 成員集的相應的 ENUM 成員,從函式返回的值是字串。

由於儲存函式和儲存過程的檢視、修改、刪除等操作幾乎相同,所以我們不再詳細講解如何操作儲存函式了。

檢視儲存函式的語法如下:

SHOW FUNCTION STATUS LIKE 儲存函式名;
SHOW CREATE FUNCTION 儲存函式名;
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=儲存函式名;

可以發現,操作儲存函式和操作儲存過程不同的是將 PROCEDURE 替換成了 FUNCTION。同樣,修改儲存函式的語法如下:

ALTER FUNCTION 儲存函式名 [ 特徵 ... ]

儲存函式的特徵與儲存過程的基本一樣。

刪除儲存過程的語法如下:

DROP FUNCTION [ IF EXISTS ] <函式名>

MySQL呼叫儲存過程和函式

儲存過程和儲存函式都是儲存在伺服器端的 SQL 語句集合。要想使用這些已經定義好的儲存過程和儲存函式就必須要通過呼叫的方式來實現。

儲存過程通過 CALL 語句來呼叫,儲存函式的使用方法與 MySQL 內部函式的使用方法相同。執行儲存過程和儲存函式需要擁有 EXECUTE 許可權(EXECUTE 許可權的資訊儲存在 information_schema 資料庫下的 USER_PRIVILEGES 表中)。

呼叫儲存過程

MySQL 中使用 CALL 語句來呼叫儲存過程。呼叫儲存過程後,資料庫系統將執行儲存過程中的 SQL 語句,然後將結果返回給輸出值。

CALL 語句接收儲存過程的名字以及需要傳遞給它的任意引數,基本語法形式如下:

CALL sp_name([parameter[...]]);

其中,sp_name 表示儲存過程的名稱,parameter 表示儲存過程的引數。

因為儲存過程實際上也是一種函式,所以儲存過程名後需要有( )符號,即使不傳遞引數也需要。

呼叫儲存函式

在 MySQL 中,儲存函式的使用方法與 MySQL 內部函式的使用方法是一樣的。換言之,使用者自己定義的儲存函式與 MySQL 內部函式是一個性質的。區別在於,儲存函式是使用者自己定義的,而內部函式是 MySQL 開發者定義的。

MySQL變數的定義和賦值

在 MySQL 中,除了支援標準的儲存過程和函式外,還引入了表示式。表示式與其它高階語言的表示式一樣,由變數、運算子和流程控制來構成。

變數是表示式語句中最基本的元素,可以用來臨時儲存資料。在儲存過程和函式中都可以定義和使用變數。使用者可以使用 DECLARE 關鍵字來定義變數,定義後可以為變數賦值。這些變數的作用範圍是 BEGIN...END 程式段中。

定義變數

MySQL 中可以使用 DECLARE 關鍵字來定義變數,其基本語法如下:

DECLARE var_name[,...] type [DEFAULT value]

其中:

  • DECLARE 關鍵字是用來宣告變數的;
  • var_name 引數是變數的名稱,這裡可以同時定義多個變數;
  • type 引數用來指定變數的型別;
  • DEFAULT value 子句將變數預設值設定為 value,沒有使用 DEFAULT 子句時,預設值為 NULL。

為變數賦值

MySQL 中可以使用 SET 關鍵字來為變數賦值,SET 語句的基本語法如下:

SET var_name = expr[,var_name = expr]...

其中:

  • SET 關鍵字用來為變數賦值;
  • var_name 引數是變數的名稱;
  • expr 引數是賦值表示式。

注意:一個 SET 語句可以同時為多個變數賦值,各個變數的賦值語句之間用逗號隔開。

MySQL 中還可以使用 SELECT..INTO 語句為變數賦值。其基本語法如下:

SELECT col_name [...] INTO var_name[,...]
FROM table_name WEHRE condition

其中:

  • col_name 參數列示查詢的欄位名稱;
  • var_name 引數是變數的名稱;
  • table_name 引數指表的名稱;
  • condition 引數指查詢條件。

注意:當將查詢結果賦值給變數時,該查詢語句的返回結果只能是單行。

MySQL定義條件和處理程式

在程式的執行過程中可能會遇到問題,此時我們可以通過定義條件和處理程式來事先定義這些問題。

定義條件是指事先定義程式執行過程中遇到的問題,處理程式定義了在遇到這些問題時應當採取的處理方式和解決辦法,保證儲存過程和函式在遇到警告或錯誤時能繼續執行,從而增強程式處理問題的能力,避免程式出現異常被停止執行。

定義條件

MySQL 中可以使用 DECLARE 關鍵字來定義條件。其基本語法如下:

DECLARE condition_name CONDITION FOR condition_value
condition value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code

其中:

  • condition_name 參數列示條件的名稱;
  • condition_value 參數列示條件的型別;
  • sqlstate_value 引數和 mysql_error_code 引數都可以表示 MySQL 的錯誤。sqlstate_value 表示長度為 5 的字串型別錯誤程式碼,mysql_error_code 表示數值型別錯誤程式碼。例如 ERROR 1146(42S02) 中,sqlstate_value 值是 42S02,mysql_error_code 值是 1146。

定義處理程式

MySQL 中可以使用 DECLARE 關鍵字來定義處理程式。其基本語法如下:

DECLARE handler_type HANDLER FOR condition_value[...] sp_statement
handler_type:
CONTINUE | EXIT | UNDO
condition_value:
SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code

其中,handler_type 引數指明錯誤的處理方式,該引數有 3 個取值。這 3 個取值分別是 CONTINUE、EXIT 和 UNDO。

  • CONTINUE 表示遇到錯誤不進行處理,繼續向下執行;
  • EXIT 表示遇到錯誤後馬上退出;
  • UNDO 表示遇到錯誤後撤回之前的操作,MySQL 中暫時還不支援這種處理方式。

注意:通常情況下,執行過程中遇到錯誤應該立刻停止執行下面的語句,並且撤回前面的操作但是,MySQL 中現在還不能支援 UNDO 操作因此,遇到錯誤時最好執行 EXIT 操作。如果事先能夠預測錯誤型別,並且進行相應的處理,那麼可以執行 CONTINUE 操作。

引數指明錯誤型別,該引數有 6 個取值:

  • sqlstate_value:包含 5 個字元的字串錯誤值;
  • condition_name:表示 DECLARE 定義的錯誤條件名稱;
  • SQLWARNING:匹配所有以 01 開頭的 sqlstate_value 值;
  • NOT FOUND:匹配所有以 02 開頭的 sqlstate_value 值;
  • SQLEXCEPTION:匹配所有沒有被 SQLWARNING 或 NOT FOUND 捕獲的 sqlstate_value 值;
  • mysql_error_code:匹配數值型別錯誤程式碼。

sp_statement 引數為程式語句段,表示在遇到定義的錯誤時,需要執行的一些儲存過程或函式。

例子:下面是定義處理程式的幾種方式,程式碼如下:

//方法一:捕獲 sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='CAN NOT FIND';

//方法二:捕獲 mysql_error_code
DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';

//方法三:先定義條件,然後呼叫
DECLARE can_not_find CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND';

//方法四:使用 SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';

//方法五:使用 NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';

//方法六:使用 SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';

上述程式碼是 6 種定義處理程式的方法。

  1. 捕獲 sqlstate_value 值。如果遇到 sqlstate_value 值為 42S02,執行 CONTINUE 操作,並且輸出“CAN NOT FIND”資訊。
  2. 捕獲 mysql_error_code 值。如果遇到 mysql_error_code 值為 1146, 執行 CONTINUE 操作,並且輸出“CAN NOT FIND”資訊。
  3. 先定義條件,然後再呼叫條件。這裡先定義 can_not_find 條件,遇到 1146 錯誤就執行 CONTINUE 操作。
  4. 使用 SQLWARNING。SQLWARNING 捕獲所有以 01 開頭的 sqlstate_value 值,然後執行 EXIT 操作,並且輸出“ERROR"資訊。
  5. 使用 NOT FOUND。NOT FOUND 捕獲所有以 02 開頭的 sqlstate_value 值,然後執行 EXIT 操作,並且輸出“CAN NOT FIND”資訊。
  6. 使用 SQLEXCEPTION。 SQLEXCEPTION 捕獲所有沒有被 SQLWARNING 或 NOT FOUND 捕獲的 sqlstate_value 值,然後執行 EXIT 操作,並且輸出“ERROR”資訊。

定義條件和處理順序,具體的執行過程如下:

mysql> CREATE TABLE t8(s1 INT,PRIMARY KEY(s1));
Query OK, 0 rows affected (0.07 sec)

mysql> DELIMITER //
mysql> CREATE PROCEDURE handlerdemo()
    -> BEGIN
    -> DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @X2=1;
    -> SET @X=1;
    -> INSERT INTO t8 VALUES(1);
    -> SET @X=2;
    -> INSERT INTO t8 VALUES(1);
    -> SET @X=3;
    -> END //
Query OK, 0 rows affected (0.02 sec)

mysql> DELIMITER ;
mysql> CALL handlerdemo();
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @X;
+------+
| @X   |
+------+
|    3 |
+------+
1 row in set (0.00 sec)

上述程式碼中,@X 是一個使用者變數,執行結果 @X 等於 3,這表明 MySQL 執行到程式的末尾。

如果DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @X2=1;這一行不存在,第二個 INSERT 因 PRIMARY KEY 約束而失敗之後,MySQL 可能已經採取 EXIT 策略,且 SELECT @X 可能已經返回 2。

注意:@X 表示使用者變數,使用 SET 語句為其賦值,使用者變數與連線有關,一個客戶端定義的變數不能被其他客戶端所使用,當客戶端退出時,該客戶端連線的所有變數將自動釋放。

MySQL遊標的定義及使用

在 MySQL 中,儲存過程或函式中的查詢有時會返回多條記錄,而使用簡單的 SELECT 語句,沒有辦法得到第一行、下一行或前十行的資料,這時可以使用遊標來逐條讀取查詢結果集中的記錄。遊標在部分資料中也被稱為游標。

關聯式資料庫管理系統實質是面向集合的,在 MySQL 中並沒有一種描述表中單一記錄的表達形式,除非使用 WHERE 子句來限制只有一條記錄被選中。所以有時我們必須藉助於遊標來進行單條記錄的資料處理。

一般通過遊標定位到結果集的某一行進行資料修改。結果集是符合 SQL 語句的所有記錄的集合。

個人理解遊標就是一個標識,用來標識資料取到了什麼地方,可以把他理解成陣列中的下標。

不像多數 DBMS,MySQL 遊標只能用於儲存過程和函式。

宣告遊標

MySQL 中使用 DECLARE 關鍵字來宣告遊標,並定義相應的 SELECT 語句,根據需要新增 WHERE 和其它子句。其語法的基本形式如下:

DECLARE cursor_name CURSOR FOR select_statement;

其中,cursor_name 表示遊標的名稱;select_statement 表示 SELECT 語句,可以返回一行或多行資料。

開啟遊標

宣告遊標之後,要想從遊標中提取資料,必須首先開啟遊標。在 MySQL 中,開啟遊標通過 OPEN 關鍵字來實現,其語法格式如下:

OPEN cursor_name;

其中,cursor_name 表示所要開啟遊標的名稱。需要注意的是,開啟一個遊標時,遊標並不指向第一條記錄,而是指向第一條記錄的前邊。

在程式中,一個遊標可以開啟多次。使用者開啟遊標後,其他使用者或程式可能正在更新資料表,所以有時會導致使用者每次開啟遊標後,顯示的結果都不同。

使用遊標

遊標順利開啟後,可以使用 FETCH...INTO 語句來讀取資料,其語法形式如下:

FETCH cursor_name INTO var_name [,var_name]...

上述語句中,將遊標 cursor_name 中 SELECT 語句的執行結果儲存到變數引數 var_name 中。變數引數 var_name 必須在遊標使用之前定義。使用遊標類似高階語言中的陣列遍歷,當第一次使用遊標時,此時遊標指向結果集的第一條記錄。

MySQL 的遊標是隻讀的,也就是說,你只能順序地從開始往後讀取結果集,不能從後往前,也不能直接跳到中間的記錄。

關閉遊標

遊標使用完畢後,要及時關閉,在 MySQL 中,使用 CLOSE 關鍵字關閉遊標,其語法格式如下:

CLOSE cursor_name;

CLOSE 釋放遊標使用的所有內部記憶體和資源,因此每個遊標不再需要時都應該關閉。

在一個遊標關閉後,如果沒有重新開啟,則不能使用它。但是,使用宣告過的遊標不需要再次宣告,用 OPEN 語句開啟它就可以了。

如果你不明確關閉遊標,MySQL 將會在到達 END 語句時自動關閉它。遊標關閉之後,不能使用 FETCH 來使用該遊標。

MySQL流程控制語句詳解

在儲存過程和自定義函式中可以使用流程控制語句來控制程式的流程。MySQL 中流程控制語句有:IF 語句、CASE 語句、LOOP 語句、LEAVE 語句、ITERATE 語句、REPEAT 語句和 WHILE 語句等。

IF語句

IF 語句用來進行條件判斷,根據是否滿足條件(可包含多個條件),來執行不同的語句,是流程控制中最常用的判斷語句。其語法的基本形式如下:

IF search_condition THEN statement_list
    [ELSEIF search_condition THEN statement_list]...
    [ELSE statement_list]
END IF

其中,search_condition 參數列示條件判斷語句,如果返回值為 TRUE ,相應的 SQL 語句列表(statement_list)被執行;如果返回值為 FALSE,則 ELSE 子句的語句列表被執行。statement_list 可以包括一個或多個語句。

注意:MySQL 中的 IF( ) 函式不同於這裡的 IF 語句。

CASE語句

CASE 語句也是用來進行條件判斷的,它提供了多個條件進行選擇,可以實現比 IF 語句更復雜的條件判斷。CASE 語句的基本形式如下:

CASE case_value
    WHEN when_value THEN statement_list
    [WHEN when_value THEN statement_list]...
    [ELSE statement_list]
END CASE

其中:

  • case_value 參數列示條件判斷的變數,決定了哪一個 WHEN 子句會被執行;
  • when_value 參數列示變數的取值,如果某個 when_value 表示式與 case_value 變數的值相同,則執行對應的 THEN 關鍵字後的 statement_list 中的語句;
  • statement_list 參數列示 when_value 值沒有與 case_value 相同值時的執行語句。
  • CASE 語句都要使用 END CASE 結束。

CASE 語句還有另一種形式。該形式的語法如下:

CASE
    WHEN search_condition THEN statement_list
    [WHEN search_condition THEN statement_list] ...
    [ELSE statement_list]
END CASE

其中,search_condition 參數列示條件判斷語句;statement_list 參數列示不同條件的執行語句。

與上述語句不同的是,該語句中的 WHEN 語句將被逐個執行,直到某個 search_condition 表示式為真,則執行對應 THEN 關鍵字後面的 statement_list 語句。如果沒有條件匹配,ELSE 子句裡的語句被執行。

這裡介紹的 CASE 語句與“控制流程函式”裡描述的 SQL CASE 表示式的 CASE 語句有輕微的不同。這裡的 CASE 語句不能有 ELSE NULL 語句,並且用 END CASE 替代 END 來終止。

LOOP 語句

LOOP 語句可以使某些特定的語句重複執行。與 IF 和 CASE 語句相比,LOOP 只實現了一個簡單的迴圈,並不進行條件判斷。

LOOP 語句本身沒有停止迴圈的語句,必須使用 LEAVE 語句等才能停止迴圈,跳出迴圈過程。LOOP 語句的基本形式如下:

[begin_label:]LOOP
    statement_list
END LOOP [end_label]

其中,begin_label 引數和 end_label 引數分別表示迴圈開始和結束的標誌,這兩個標誌必須相同,而且都可以省略;statement_list 參數列示需要迴圈執行的語句。

LEAVE 語句

LEAVE 語句主要用於跳出迴圈控制。其語法形式如下:

LEAVE label

其中,label 參數列示迴圈的標誌,LEAVE 語句必須跟在迴圈標誌前面。

ITERATE 語句

ITERATE 是“再次迴圈”的意思,用來跳出本次迴圈,直接進入下一次迴圈。ITERATE 語句的基本語法形式如下:

ITERATE label

其中,label 參數列示迴圈的標誌,ITERATE 語句必須跟在迴圈標誌前面。

說明:LEAVE 語句和 ITERATE 語句都用來跳出迴圈語句,但兩者的功能是不一樣的。LEAVE 語句是跳出整個迴圈,然後執行迴圈後面的程式。而 ITERATE 語句是跳出本次迴圈,然後進入下一次迴圈。使用這兩個語句時一定要區分清楚。

REPEAT 語句

REPEAT 語句是有條件控制的迴圈語句,每次語句執行完畢後,會對條件表示式進行判斷,如果表示式返回值為 TRUE,則迴圈結束,否則重複執行迴圈中的語句。

REPEAT 語句的基本語法形式如下:

[begin_label:] REPEAT
  statement_list
  UNTIL search_condition
END REPEAT [end_label]

其中:

  • begin_label 為 REPEAT 語句的標註名稱,該引數可以省略;
  • REPEAT 語句內的語句被重複,直至 search_condition 返回值為 TRUE。
  • statement_list 參數列示迴圈的執行語句;
  • search_condition 參數列示結束迴圈的條件,滿足該條件時迴圈結束。
  • REPEAT 迴圈都用 END REPEAT 結束。

WHILE 語句

WHILE 語句也是有條件控制的迴圈語句。WHILE 語句和 REPEAT 語句不同的是,WHILE 語句是當滿足條件時,執行迴圈內的語句,否則退出迴圈。WHILE 語句的基本語法形式如下:

[begin_label:] WHILE search_condition DO
  statement list
END WHILE [end label]

其中,search_condition 參數列示迴圈執行的條件,滿足該條件時迴圈執行;statement_list 參數列示迴圈的執行語句。WHILE 迴圈需要使用 END WHILE 來結束。

相關文章