1. 程式人生 > 其它 >SQL 語法速成手冊,yyds!

SQL 語法速成手冊,yyds!

本文針對關係型資料庫的一般語法。限於篇幅,本文側重說明用法,不會展開講解特性、原理。

一、基本概念

資料庫術語

  • 資料庫(database) - 儲存有組織的資料的容器(通常是一個檔案或一組檔案)。

  • 資料表(table) - 某種特定型別資料的結構化清單。

  • 模式(schema) - 關於資料庫和表的佈局及特性的資訊。模式定義了資料在表中如何儲存,包含儲存什麼樣的資料,資料如何分解,各部分資訊如何命名等資訊。資料庫和表都有模式。

  • 列(column) - 表中的一個欄位。所有表都是由一個或多個列組成的。

  • 行(row) - 表中的一個記錄。

  • 主鍵(primary key) - 一列(或一組列),其值能夠唯一標識表中每一行。

SQL 語法

SQL(Structured Query Language),標準 SQL 由 ANSI 標準委員會管理,從而稱為 ANSI SQL。各個 DBMS 都有自己的實現,如 PL/SQL、Transact-SQL 等。

SQL 語法結構

SQL 語法結構包括:

  • 子句 - 是語句和查詢的組成成分。(在某些情況下,這些都是可選的。)

  • 表示式 - 可以產生任何標量值,或由列和行的資料庫表

  • 謂詞 - 給需要評估的 SQL 三值邏輯(3VL)(true/false/unknown)或布林真值指定條件,並限制語句和查詢的效果,或改變程式流程。

  • 查詢 - 基於特定條件檢索資料。這是 SQL 的一個重要組成部分。

  • 語句 - 可以持久地影響綱要和資料,也可以控制資料庫事務、程式流程、連線、會話或診斷。

SQL 語法要點

  • SQL 語句不區分大小寫,但是資料庫表名、列名和值是否區分,依賴於具體的 DBMS 以及配置。
    例如:SELECT 與 select 、Select 是相同的。

  • 多條 SQL 語句必須以分號(;)分隔。

  • 處理 SQL 語句時,所有空格都被忽略。SQL 語句可以寫成一行,也可以分寫為多行。

--一行SQL語句
UPDATEuserSETusername='robot',password='robot'WHEREusername='root';

--多行SQL語句
UPDATEuser
SETusername='robot',password='robot'
WHEREusername='root';
  • SQL 支援三種註釋

##註釋1
--註釋2
/*註釋3*/

SQL 分類

資料定義語言(DDL)

資料定義語言(Data Definition Language,DDL)是 SQL 語言集中負責資料結構定義與資料庫物件定義的語言。

DDL 的主要功能是定義資料庫物件。

DDL 的核心指令是 CREATE、ALTER、DROP。

資料操縱語言(DML)

資料操縱語言(Data Manipulation Language, DML)是用於資料庫操作,對資料庫其中的物件和資料執行訪問工作的程式設計語句。

DML 的主要功能是 訪問資料,因此其語法都是以讀寫資料庫為主。

DML 的核心指令是 INSERT、UPDATE、DELETE、SELECT。這四個指令合稱 CRUD(Create, Read, Update, Delete),即增刪改查。

事務控制語言(TCL)

事務控制語言 (Transaction Control Language, TCL) 用於管理資料庫中的事務。這些用於管理由 DML 語句所做的更改。它還允許將語句分組為邏輯事務。

TCL 的核心指令是 COMMIT、ROLLBACK。

資料控制語言(DCL)

資料控制語言 (Data Control Language, DCL) 是一種可對資料訪問權進行控制的指令,它可以控制特定使用者賬戶對資料表、查看錶、預存程式、使用者自定義函式等資料庫物件的控制權。

DCL 的核心指令是 GRANT、REVOKE。

DCL 以控制使用者的訪問許可權為主,因此其指令做法並不複雜,可利用 DCL 控制的許可權有:CONNECT、SELECT、INSERT、UPDATE、DELETE、EXECUTE、USAGE、REFERENCES。

根據不同的 DBMS 以及不同的安全性實體,其支援的許可權控制也有所不同。

(以下為 DML 語句用法)

二、增刪改查

增刪改查,又稱為 CRUD,資料庫基本操作中的基本操作。

插入資料

INSERT INTO 語句用於向表中插入新記錄。

插入完整的行

INSERTINTOuser
VALUES(10,'root','root','[email protected]');

插入行的一部分

INSERTINTOuser(username,password,email)
VALUES('admin','admin','[email protected]');

插入查詢出來的資料

INSERTINTOuser(username)
SELECTname
FROMaccount;

更新資料

UPDATE 語句用於更新表中的記錄。

UPDATEuser
SETusername='robot',password='robot'
WHEREusername='root';

刪除資料

DELETE 語句用於刪除表中的記錄。

TRUNCATE TABLE 可以清空表,也就是刪除所有行。

刪除表中的指定資料

DELETEFROMuser
WHEREusername='robot';

清空表中的資料

TRUNCATETABLEuser;

查詢資料

SELECT 語句用於從資料庫中查詢資料。

DISTINCT 用於返回唯一不同的值。它作用於所有列,也就是說所有列的值都相同才算相同。

LIMIT 限制返回的行數。可以有兩個引數,第一個引數為起始行,從 0 開始;第二個引數為返回的總行數。

ASC :升序(預設)

DESC :降序

查詢單列

SELECTprod_name
FROMproducts;

查詢多列

SELECTprod_id,prod_name,prod_price
FROMproducts;

查詢所有列

ELECT*
FROMproducts;

查詢不同的值

SELECTDISTINCT
vend_idFROMproducts;

限制查詢結果

--返回前5行
SELECT*FROMmytableLIMIT5;
SELECT*FROMmytableLIMIT0,5;
--返回第3~5行
SELECT*FROMmytableLIMIT2,3;

三、子查詢

子查詢是巢狀在較大查詢中的 SQL 查詢。子查詢也稱為內部查詢或內部選擇,而包含子查詢的語句也稱為外部查詢或外部選擇。

  • 子查詢可以巢狀在 SELECT,INSERT,UPDATE 或 DELETE 語句內或另一個子查詢中。

  • 子查詢通常會在另一個 SELECT 語句的 WHERE 子句中新增。

  • 您可以使用比較運算子,如 >,<,或 =。比較運算子也可以是多行運算子,如 IN,ANY 或 ALL。

  • 子查詢必須被圓括號 () 括起來。

  • 內部查詢首先在其父查詢之前執行,以便可以將內部查詢的結果傳遞給外部查詢。執行過程可以參考下圖:

子查詢的子查詢

SELECTcust_name,cust_contact
FROMcustomers
WHEREcust_idIN(SELECTcust_id
FROMorders
WHEREorder_numIN(SELECTorder_num
FROMorderitems
WHEREprod_id='RGAN01'));

WHERE

  • WHERE 子句用於過濾記錄,即縮小訪問資料的範圍。

  • WHERE 後跟一個返回 true 或 false 的條件。

  • WHERE 可以與 SELECT,UPDATE 和 DELETE 一起使用。

  • 可以在 WHERE 子句中使用的操作符

運算子描述
= 等於
<> 不等於。註釋:在 SQL 的一些版本中,該操作符可被寫成 !=
> 大於
< 小於
>= 大於等於
<= 小於等於
BETWEEN 在某個範圍內
LIKE 搜尋某種模式
IN 指定針對某個列的多個可能值

SELECT 語句中的 WHERE 子句

SELECT*FROMCustomers
WHEREcust_name='KidsPlace';

UPDATE 語句中的 WHERE 子句

UPDATECustomers
SETcust_name='JackJones'
WHEREcust_name='KidsPlace';

DELETE 語句中的 WHERE 子句

DELETEFROMCustomers
WHEREcust_name='KidsPlace';

IN 和 BETWEEN

  • IN 操作符在 WHERE 子句中使用,作用是在指定的幾個特定值中任選一個值。

  • BETWEEN 操作符在 WHERE 子句中使用,作用是選取介於某個範圍內的值。

IN 示例

SELECT*
FROMproducts
WHEREvend_idIN('DLL01','BRS01');

BETWEEN 示例

SELECT*
FROMproducts
WHEREprod_priceBETWEEN3AND5;

AND、OR、NOT

  • AND、OR、NOT 是用於對過濾條件的邏輯處理指令。

  • AND 優先順序高於 OR,為了明確處理順序,可以使用 ()。

  • AND 操作符表示左右條件都要滿足。

  • OR 操作符表示左右條件滿足任意一個即可。

  • NOT 操作符用於否定一個條件。

AND 示例

SELECTprod_id,prod_name,prod_price
FROMproducts
WHEREvend_id='DLL01'ANDprod_price<=4;

OR 示例

SELECTprod_id,prod_name,prod_price
FROMproducts
WHEREvend_id='DLL01'ORvend_id='BRS01';

NOT 示例

SELECT*
FROMproducts
WHEREprod_priceNOTBETWEEN3AND5;

LIKE

  • LIKE 操作符在 WHERE 子句中使用,作用是確定字串是否匹配模式。

  • 只有欄位是文字值時才使用 LIKE。

  • LIKE 支援兩個萬用字元匹配選項:% 和 _。

  • 不要濫用萬用字元,萬用字元位於開頭處匹配會非常慢。

  • % 表示任何字元出現任意次數。

  • _ 表示任何字元出現一次。

% 示例

SELECTprod_id,prod_name,prod_price
FROMproducts
WHEREprod_nameLIKE'%beanbag%';

_ 示例

SELECTprod_id,prod_name,prod_price
FROMproducts
WHEREprod_nameLIKE'__inchteddybear';

四、連線和組合

連線(JOIN)

如果一個 JOIN 至少有一個公共欄位並且它們之間存在關係,則該 JOIN 可以在兩個或多個表上工作。

連線用於連線多個表,使用 JOIN 關鍵字,並且條件語句使用 ON 而不是 WHERE。

JOIN 保持基表(結構和資料)不變。

JOIN 有兩種連線型別:內連線和外連線。

內連線又稱等值連線,使用 INNER JOIN 關鍵字。在沒有條件語句的情況下返回笛卡爾積。

  • 自連線可以看成內連線的一種,只是連線的表示自身而已。

自然連線是把同名列通過 = 測試連線起來的,同名列可以有多個。

內連線 vs 自然連線

  • 內連線提供連線的列,而自然連線自動連線所有同名列。

外連線返回一個表中的所有行,並且僅返回來自次表中滿足連線條件的那些行,即兩個表中的列是相等的。外連線分為左外連線、右外連線、全外連線(Mysql 不支援)。

  • 左外連線就是保留左表沒有關聯的行。

  • 右外連線就是保留右表沒有關聯的行。

連線 vs 子查詢

  • 連線可以替換子查詢,並且比子查詢的效率一般會更快。

內連線(INNER JOIN)

SELECTvend_name,prod_name,prod_price
FROMvendorsINNERJOINproducts
ONvendors.vend_id=products.vend_id;

自連線

SELECTc1.cust_id,c1.cust_name,c1.cust_contact
FROMcustomersc1,customersc2
WHEREc1.cust_name=c2.cust_name
ANDc2.cust_contact='JimJones';

自然連線(NATURAL JOIN)

SELECT*
FROMProducts
NATURALJOINCustomers;

左連線(LEFT JOIN)

SELECTcustomers.cust_id,orders.order_num
FROMcustomersLEFTJOINorders
ONcustomers.cust_id=orders.cust_id;

右連線(RIGHT JOIN)

SELECTcustomers.cust_id,orders.order_num
FROMcustomersRIGHTJOINorders
ONcustomers.cust_id=orders.cust_id;

組合(UNION)

UNION 運算子將兩個或更多查詢的結果組合起來,並生成一個結果集,其中包含來自 UNION 中參與查詢的提取行。

UNION 基本規則

  • 所有查詢的列數和列順序必須相同。

  • 每個查詢中涉及表的列的資料型別必須相同或相容。

  • 通常返回的列名取自第一個查詢。

預設會去除相同行,如果需要保留相同行,使用 UNION ALL。

只能包含一個 ORDER BY 子句,並且必須位於語句的最後。

應用場景

  • 在一個查詢中從不同的表返回結構資料。

  • 對一個表執行多個查詢,按一個查詢返回資料。

組合查詢

SELECTcust_name,cust_contact,cust_email
FROMcustomers
WHEREcust_stateIN('IL','IN','MI')
UNION
SELECTcust_name,cust_contact,cust_email
FROMcustomers
WHEREcust_name='Fun4All';

JOIN vs UNION

  • JOIN 中連線表的列可能不同,但在 UNION 中,所有查詢的列數和列順序必須相同。

  • UNION 將查詢之後的行放在一起(垂直放置),但 JOIN 將查詢之後的列放在一起(水平放置),即它構成一個笛卡爾積。

五、函式

注意:不同資料庫的函式往往各不相同,因此不可移植。本節主要以 Mysql 的函式為例。

文字處理

函式說明
LEFT()、RIGHT() 左邊或者右邊的字元
LOWER()、UPPER() 轉換為小寫或者大寫
LTRIM()、RTIM() 去除左邊或者右邊的空格
LENGTH() 長度
SOUNDEX() 轉換為語音值

其中, SOUNDEX() 可以將一個字串轉換為描述其語音表示的字母數字模式。

SELECT*
FROMmytable
WHERESOUNDEX(col1)=SOUNDEX('apple')

日期和時間處理

日期格式:YYYY-MM-DD

時間格式:HH:MM:SS

函 數說 明
AddDate() 增加一個日期(天、周等)
AddTime() 增加一個時間(時、分等)
CurDate() 返回當前日期
CurTime() 返回當前時間
Date() 返回日期時間的日期部分
DateDiff() 計算兩個日期之差
Date_Add() 高度靈活的日期運算函式
Date_Format() 返回一個格式化的日期或時間串
Day() 返回一個日期的天數部分
DayOfWeek() 對於一個日期,返回對應的星期幾
Hour() 返回一個時間的小時部分
Minute() 返回一個時間的分鐘部分
Month() 返回一個日期的月份部分
Now() 返回當前日期和時間
Second() 返回一個時間的秒部分
Time() 返回一個日期時間的時間部分
Year() 返回一個日期的年份部分
mysql>SELECTNOW();
2018-4-1420:25:11

數值處理

函式說明
SIN() 正弦
COS() 餘弦
TAN() 正切
ABS() 絕對值
SQRT() 平方根
MOD() 餘數
EXP() 指數
PI() 圓周率
RAND() 隨機數

彙總

函 數說 明
AVG() 返回某列的平均值
COUNT() 返回某列的行數
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

AVG() 會忽略 NULL 行。

使用 DISTINCT 可以讓彙總函式值彙總不同的值。

SELECTAVG(DISTINCTcol1)ASavg_col
FROMmytable

六、排序和分組

ORDER BY

ORDER BY 用於對結果集進行排序。

  • ASC :升序(預設)

  • DESC :降序

可以按多個列進行排序,並且為每個列指定不同的排序方式

指定多個列的排序方向

SELECT*FROMproducts
ORDERBYprod_priceDESC,prod_nameASC;

GROUP BY

  • GROUP BY 子句將記錄分組到彙總行中。

  • GROUP BY 為每個組返回一個記錄。

  • GROUP BY 通常還涉及聚合:COUNT,MAX,SUM,AVG 等。

  • GROUP BY 可以按一列或多列進行分組。

  • GROUP BY 按分組欄位進行排序後,ORDER BY 可以以彙總欄位來進行排序。

分組

SELECTcust_name,COUNT(cust_address)ASaddr_num
FROMCustomersGROUPBYcust_name;

分組後排序

SELECTcust_name,COUNT(cust_address)ASaddr_num
FROMCustomersGROUPBYcust_name
ORDERBYcust_nameDESC;

HAVING

HAVING 用於對彙總的 GROUP BY 結果進行過濾。

HAVING 要求存在一個 GROUP BY 子句。

WHERE 和 HAVING 可以在相同的查詢中。

HAVING vs WHERE

  • WHERE 和 HAVING 都是用於過濾。

  • HAVING 適用於彙總的組記錄;而 WHERE 適用於單個記錄。

使用 WHERE 和 HAVING 過濾資料

SELECTcust_name,COUNT(*)ASnum
FROMCustomers
WHEREcust_emailISNOTNULL
GROUPBYcust_name
HAVINGCOUNT(*)>=1;

(以下為 DDL 語句用法)

七、資料定義

DDL 的主要功能是定義資料庫物件(如:資料庫、資料表、檢視、索引等)。

資料庫(DATABASE)

建立資料庫

CREATEDATABASEtest;

刪除資料庫

DROPDATABASEtest;

選擇資料庫

USEtest;

資料表(TABLE)

建立資料表

普通建立

CREATETABLEuser(
idint(10)unsignedNOTNULLCOMMENT'Id',
usernamevarchar(64)NOTNULLDEFAULT'default'COMMENT'使用者名稱',
passwordvarchar(64)NOTNULLDEFAULT'default'COMMENT'密碼',
emailvarchar(64)NOTNULLDEFAULT'default'COMMENT'郵箱'
)COMMENT='使用者表';

根據已有的表建立新表

CREATETABLEvip_userAS
SELECT*FROMuser;

刪除資料表

DROPTABLEuser;

修改資料表

新增列

ALTERTABLEuser
ADDageint(3);

刪除列

ALTERTABLEuser
DROPCOLUMNage;

修改列

ALTERTABLE`user`
MODIFYCOLUMNagetinyint;

新增主鍵

ALTERTABLEuser
ADDPRIMARYKEY(id);

刪除主鍵

ALTERTABLEuser
DROPPRIMARYKEY;

檢視(VIEW)

定義

  • 檢視是基於 SQL 語句的結果集的視覺化的表。

  • 檢視是虛擬的表,本身不包含資料,也就不能對其進行索引操作。對檢視的操作和對普通表的操作一樣。

作用

  • 簡化複雜的 SQL 操作,比如複雜的聯結;

  • 只使用實際表的一部分資料;

  • 通過只給使用者訪問檢視的許可權,保證資料的安全性;

  • 更改資料格式和表示。

建立檢視

CREATEVIEWtop_10_user_viewAS
SELECTid,username
FROMuser
WHEREid<10;

刪除檢視

DROPVIEWtop_10_user_view;

索引(INDEX)

作用

  • 通過索引可以更加快速高效地查詢資料。

  • 使用者無法看到索引,它們只能被用來加速查詢。

注意

  • 更新一個包含索引的表需要比更新一個沒有索引的表花費更多的時間,這是由於索引本身也需要更新。因此,買二手手機號地圖理想的做法是僅僅在常常被搜尋的列(以及表)上面建立索引。

唯一索引

  • 唯一索引表明此索引的每一個索引值只對應唯一的資料記錄。

建立索引

CREATEINDEXuser_index
ONuser(id);

建立唯一索引

CREATEUNIQUEINDEXuser_index
ONuser(id);

刪除索引

ALTERTABLEuser
DROPINDEXuser_index;

約束

SQL 約束用於規定表中的資料規則。

如果存在違反約束的資料行為,行為會被約束終止。

約束可以在建立表時規定(通過 CREATE TABLE 語句),或者在表建立之後規定(通過 ALTER TABLE 語句)。

約束型別

  • NOT NULL - 指示某列不能儲存 NULL 值。

  • UNIQUE - 保證某列的每行必須有唯一的值。

  • PRIMARY KEY - NOT NULL 和 UNIQUE 的結合。確保某列(或兩個列多個列的結合)有唯一標識,有助於更容易更快速地找到表中的一個特定的記錄。

  • FOREIGN KEY - 保證一個表中的資料匹配另一個表中的值的參照完整性。

  • CHECK - 保證列中的值符合指定的條件。

  • DEFAULT - 規定沒有給列賦值時的預設值。

建立表時使用約束條件:

CREATETABLEUsers(
IdINT(10)UNSIGNEDNOTNULLAUTO_INCREMENTCOMMENT'自增Id',
UsernameVARCHAR(64)NOTNULLUNIQUEDEFAULT'default'COMMENT'使用者名稱',
PasswordVARCHAR(64)NOTNULLDEFAULT'default'COMMENT'密碼',
EmailVARCHAR(64)NOTNULLDEFAULT'default'COMMENT'郵箱地址',
EnabledTINYINT(4)DEFAULTNULLCOMMENT'是否有效',
PRIMARYKEY(Id)
)ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8mb4COMMENT='使用者表';

(以下為 TCL 語句用法)

八、事務處理

不能回退 SELECT 語句,回退 SELECT 語句也沒意義;也不能回退 CREATE 和 DROP 語句。

MySQL 預設是隱式提交,每執行一條語句就把這條語句當成一個事務然後進行提交。當出現 START TRANSACTION 語句時,會關閉隱式提交;當 COMMIT 或 ROLLBACK 語句執行後,事務會自動關閉,重新恢復隱式提交。

通過 set autocommit=0 可以取消自動提交,直到 set autocommit=1 才會提交;autocommit 標記是針對每個連線而不是針對伺服器的。

指令

  • START TRANSACTION - 指令用於標記事務的起始點。

  • SAVEPOINT - 指令用於建立保留點。

  • ROLLBACK TO - 指令用於回滾到指定的保留點;如果沒有設定保留點,則回退到 START TRANSACTION 語句處。

  • COMMIT - 提交事務。

--開始事務
STARTTRANSACTION;

--插入操作A
INSERTINTO`user`
VALUES(1,'root1','root1','[email protected]');

--建立保留點updateA
SAVEPOINTupdateA;

--插入操作B
INSERTINTO`user`
VALUES(2,'root2','root2','[email protected]');

--回滾到保留點updateA
ROLLBACKTOupdateA;

--提交事務,只有操作A生效
COMMIT;

(以下為 DCL 語句用法)

九、許可權控制

GRANT 和 REVOKE 可在幾個層次上控制訪問許可權:

  • 整個伺服器,使用 GRANT ALL 和 REVOKE ALL;

  • 整個資料庫,使用 ON database.*;

  • 特定的表,使用 ON database.table;

  • 特定的列;

  • 特定的儲存過程。

新建立的賬戶沒有任何許可權。

賬戶用 username@host 的形式定義,username@% 使用的是預設主機名。

MySQL 的賬戶資訊儲存在 mysql 這個資料庫中。

USEmysql;
SELECTuserFROMuser;

建立賬戶

CREATEUSERmyuserIDENTIFIEDBY'mypassword';

修改賬戶名

UPDATEuserSETuser='newuser'WHEREuser='myuser';
FLUSHPRIVILEGES;

刪除賬戶

DROPUSERmyuser;

檢視許可權

SHOWGRANTSFORmyuser;

授予許可權

GRANTSELECT,INSERTON*.*TOmyuser;

刪除許可權

REVOKESELECT,INSERTON*.*FROMmyuser;

更改密碼

SETPASSWORDFORmyuser='mypass';

十、儲存過程

儲存過程可以看成是對一系列 SQL 操作的批處理;

使用儲存過程的好處

  • 程式碼封裝,保證了一定的安全性;

  • 程式碼複用;

  • 由於是預先編譯,因此具有很高的效能。

建立儲存過程

  • 命令列中建立儲存過程需要自定義分隔符,因為命令列是以 ; 為結束符,而儲存過程中也包含了分號,因此會錯誤把這部分分號當成是結束符,造成語法錯誤。

  • 包含 in、out 和 inout 三種引數。

  • 給變數賦值都需要用 select into 語句。

  • 每次只能給一個變數賦值,不支援集合的操作。

建立儲存過程

DROPPROCEDUREIFEXISTS`proc_adder`;
DELIMITER;;
CREATEDEFINER=`root`@`localhost`PROCEDURE`proc_adder`(INaint,INbint,OUTsumint)
BEGIN
DECLAREcint;
ifaisnullthenseta=0;
endif;

ifbisnullthensetb=0;
endif;

setsum=a+b;
END
;;
DELIMITER;

使用儲存過程

set@b=5;
callproc_adder(2,@b,@s);
select@sassum;

十一、遊標

遊標(cursor)是一個儲存在 DBMS 伺服器上的資料庫查詢,它不是一條 SELECT 語句,而是被該語句檢索出來的結果集。

在儲存過程中使用遊標可以對一個結果集進行移動遍歷。

遊標主要用於互動式應用,其中使用者需要對資料集中的任意行進行瀏覽和修改。

使用遊標的四個步驟:

  • 宣告遊標,這個過程沒有實際檢索出資料;

  • 開啟遊標;

  • 取出資料;

  • 關閉遊標;

DELIMITER$
CREATEPROCEDUREgetTotal()
BEGIN
DECLAREtotalINT;
--建立接收遊標資料的變數
DECLAREsidINT;
DECLAREsnameVARCHAR(10);
--建立總數變數
DECLAREsageINT;
--建立結束標誌變數
DECLAREdoneINTDEFAULTfalse;
--建立遊標
DECLAREcurCURSORFORSELECTid,name,agefromcursor_tablewhereage>30;
--指定遊標迴圈結束時的返回值
DECLARECONTINUEHANDLERFORNOTFOUNDSETdone=true;
SETtotal=0;
OPENcur;
FETCHcurINTOsid,sname,sage;
WHILE(NOTdone)
DO
SETtotal=total+1;
FETCHcurINTOsid,sname,sage;
ENDWHILE;

CLOSEcur;
SELECTtotal;
END$
DELIMITER;

--呼叫儲存過程
callgetTotal();

十二、觸發器

觸發器是一種與表操作有關的資料庫物件,當觸發器所在表上出現指定事件時,將呼叫該物件,即表的操作事件觸發表上的觸發器的執行。

可以使用觸發器來進行審計跟蹤,把修改記錄到另外一張表中。

MySQL 不允許在觸發器中使用 CALL 語句 ,也就是不能呼叫儲存過程。

BEGIN 和 END

當觸發器的觸發條件滿足時,將會執行 BEGIN 和 END 之間的觸發器執行動作。

注意:在 MySQL 中,分號 ; 是語句結束的識別符號,遇到分號表示該段語句已經結束,MySQL 可以開始執行了。因此,直譯器遇到觸發器執行動作中的分號後就開始執行,然後會報錯,因為沒有找到和 BEGIN 匹配的 END。

這時就會用到 DELIMITER 命令(DELIMITER 是定界符,分隔符的意思)。它是一條命令,不需要語句結束標識,語法為:DELIMITER new_delemiter。new_delemiter 可以設為 1 個或多個長度的符號,預設的是分號;,我們可以把它修改為其他符號,如$- DELIMITER $。在這之後的語句,以分號結束,直譯器不會有什麼反應,只有遇到了$,才認為是語句結束。注意,使用完之後,我們還應該記得把它給修改回來。

NEW 和 OLD

  • MySQL 中定義了 NEW 和 OLD 關鍵字,用來表示觸發器的所在表中,觸發了觸發器的那一行資料。

  • 在 INSERT 型觸發器中,NEW 用來表示將要(BEFORE)或已經(AFTER)插入的新資料;

  • 在 UPDATE 型觸發器中,OLD 用來表示將要或已經被修改的原資料,NEW 用來表示將要或已經修改為的新資料;

  • 在 DELETE 型觸發器中,OLD 用來表示將要或已經被刪除的原資料;

  • 使用方法:NEW.columnName (columnName 為相應資料表某一列名)

建立觸發器

提示:為了理解觸發器的要點,有必要先了解一下建立觸發器的指令。

CREATE TRIGGER 指令用於建立觸發器。

語法:

CREATETRIGGERtrigger_name
trigger_time
trigger_event
ONtable_name
FOREACHROW
BEGIN
trigger_statements
END;

說明:

  • trigger_name:觸發器名

  • trigger_time: 觸發器的觸發時機。取值為 BEFORE 或 AFTER。

  • trigger_event: 觸發器的監聽事件。取值為 INSERT、UPDATE 或 DELETE。

  • table_name: 觸發器的監聽目標。指定在哪張表上建立觸發器。

  • FOR EACH ROW: 行級監視,Mysql 固定寫法,其他 DBMS 不同。

  • trigger_statements: 觸發器執行動作。是一條或多條 SQL 語句的列表,列表內的每條語句都必須用分號 ; 來結尾。

示例:

DELIMITER$
CREATETRIGGER`trigger_insert_user`
AFTERINSERTON`user`
FOREACHROW
BEGIN
INSERTINTO`user_history`(user_id,operate_type,operate_time)
VALUES(NEW.id,'addauser',now());
END$
DELIMITER;

檢視觸發器

SHOWTRIGGERS;

刪除觸發器

DROPTRIGGERIFEXISTStrigger_insert_user;