函數
函數:系統函數和自定義函數
系統函數:https://dev.mysql.com/doc/refman/8.0/en/func-op-summary-ref.html
函數也可以進入數據庫之後利用help命令來查看幫助,比如help max
自定義函數 (user-defined function UDF)
- 注自定義函數定義之後保存在mysql.proc(mysql.func)表中
- 創建UDF
CREATE [AGGREGATE] FUNCTION function_name(parameter_name type,[parameter_name type,...]) RETURNS {STRING|INTEGER|REAL}
runtime_body - 說明:
參數可以有多個,也可以沒有參數
必須得有,且只能有一個返回值
創建函數
示例1:無參UDF
CREATE FUNCTION simpleFun() RETURNS VARCHAR(20)
RETURN "Hello World!”;
- 查看自定義的函數列表:
SHOW FUNCTION STATUS;
select * from mysql.proc(mysql.func)\G; - 查看函數定義
SHOW CREATE FUNCTION function_name; - 查看函數的code
SHWO FUNCTION CODE; - 刪除UDF:
DROP FUNCTION function_name; - 調用自定義函數語法:
SELECT function_name(parameter_value,...);
示例2:有參數UDF
DELIMITER //
CREATE FUNCTION deleteById(uid SMALLINT UNSIGNED) RETURNS
VARCHAR(20)
BEGIN
DELETE FROM students WHERE stuid = uid;
RETURN (SELECT COUNT(stuid) FROM students);
END//
DELIMITER ;
- 其中的delimiter代表分隔符,先切換成//(也可以寫其他的符號),然後函數定義完了之後再切換回;
- 這樣做用於避免函數的的內容被執行,因爲函數體內的命令有分號作爲結尾,不先修改分隔符的話會被當做命令來執行。
自定義函數中定義局部變量語法
DECLARE 變量1[,變量2,... ] 變量類型 [DEFAULT 默認值]
- 說明:局部變量的作用範圍是在BEGIN...END程序中,而且定義局部變量語句必須在BEGIN...END的第一行定義
示例3:
DELIMITER //
CREATE FUNCTION addTwoNumber(x SMALLINT UNSIGNED, Y SMALLINT
UNSIGNED) RETURNS SMALLINT
BEGIN
DECLARE a, b SMALLINT UNSIGNED;
SET a = x, b = y;
RETURN a+b;
END//
DELIMITER ;
- 在這裏的函數中定義本地變量的時候,要使用declare命令(主義和set區別),一行中的變量的類型只需要寫一次(寫在最後)即可,它代表把前面所有的變量都定義爲這種類型的
- 寫在begin和and之間進行定義的變量都是局部變量,在這裏類似C語言,且變量前面不用加任何符號直接定義和使用即可
爲變量賦值語法
SET @parameter_name = value[,parameter_name = value...]
SELECT ... INTO parameter_name
示例4:
...
DECLARE x int;
SELECT COUNT(id) FROM tdb_name INTO x;
RETURN x;
END//
存儲過程
存儲過程優勢
- 存儲過程把經常使用的SQL語句或業務邏輯封裝起來,預編譯保存在數據庫中,當需要時從數據庫中直接調用,省去了編譯的過程
- 提高了運行速度
- 同時降低網絡數據傳輸量
存儲過程與自定義函數的區別 - 存儲過程實現的過程要複雜一些,而函數的針對性較強
- 存儲過程可以有多個返回值,而自定義函數只有一個返回值
- 存儲過程一般可獨立執行,而函數往往是作爲其他SQL語句的一部分來使用
存儲過程:存儲過程保存在mysql.proc表中
- 創建存儲過程
CREATE PROCEDURE sp_name ([ proc_parameter [,proc_parameter ...]]) routime_body
proc_parameter : [IN|OUT|INOUT] parameter_name type
其中IN表示輸入參數,OUT表示輸出參數,INOUT表示既可以輸入也可以輸出;param_name表示參數名稱;type表示參數的類型 - 查看存儲過程列表
SHOW PROCEDURE STATUS;
select * from mysql.proc\G; - 查看存儲過程定義
SHOW CREATE PROCEDURE sp_name - 調用存儲過程
CALL sp_name ([ proc_parameter [,proc_parameter ...]])
CALL sp_name
說明:當無參時,可以省略"()",當有參數時,不可省略"()” - 存儲過程修改
ALTER語句修改存儲過程只能修改存儲過程的註釋等無關緊要的東西,不能修改存儲過程體,所以要修改存儲過程,方法就是刪除重建 - 刪除存儲過程
DROP PROCEDURE [IF EXISTS] sp_name
存儲過程示例
- 創建無參存儲過程
delimiter //
CREATE PROCEDURE showTime()
BEGIN
SELECT now();
END//
delimiter ;
CALL showTime;
- 創建含參存儲過程:只有一個IN參數
delimiter //
CREATE PROCEDURE selectById(IN uid SMALLINT UNSIGNED)
BEGIN
SELECT * FROM students WHERE stuid = uid;
END//
delimiter ;
call selectById(2);
- 創建包含有會話級全局變量的存儲過程
delimiter //
CREATE PROCEDURE dorepeat(n INT)
BEGIN
SET @i = 0;
SET @sum = 0;
REPEAT SET @sum = @sum+@i; SET @i = @i + 1;
UNTIL @i > n END REPEAT;
END//
delimiter ;
CALL dorepeat(100);
SELECT @sum;
- 注意這裏用到了循環體repeat ... until ... END repeat;
- 因爲是用set命令定義的自定義的變量,所以就算在存儲過程外也能夠直接使用它。
- 在這裏用了set定義會話級全局變量的方式把過程內的結果傳入到外面,更簡單的方法就是下面4中的定義一個OUT參數,用它把結果傳到外面(不過也得利用外部的會話級自定義全局變量接收)。
- 創建含參存儲過程:包含IN參數和OUT參數
delimiter //
CREATE PROCEDURE deleteById(IN uid SMALLINT UNSIGNED, OUT num SMALLINT UNSIGNED)
BEGIN
DELETE FROM students WHERE stuid >= uid;
SELECT row_count() into num; #注意這裏的形參並沒有用@,看注意點7
END//
delimiter ;
call deleteById(2,@Line);
SELECT @Line;
- 說明:創建存儲過程deleteById,包含一個IN參數和一個OUT參數.調用時,傳入刪除的ID和保存被修改的行的數值的用戶變量@Line
- 然後用select @Line;輸出被修改後的行的值(這裏也就指的是被刪除掉了多少行的行數值,刪除這些行的判斷條件由傳入的參數uid指定)。
- 可用help row_count 查看此函數的解釋
流程控制
存儲過程和函數中可以使用流程控制來控制語句的執行
流程控制:
- IF:用來進行條件判斷。根據是否滿足條件,執行不同語句
- CASE:用來進行條件判斷,可實現比IF語句更復雜的條件判斷
- LOOP:重複執行特定的語句,實現一個簡單的循環
- LEAVE:用於跳出循環控制 (類似break)
- ITERATE:跳出本次循環,然後直接進入下一次循環 (類似continue)
- REPEAT:有條件控制的循環語句。當滿足特定條件時,就會跳出循環語句
- WHILE:有條件控制的循環語句
trigger觸發器(類似ansible中的handler)
觸發器的執行不是由程序調用,也不是由手工啓動,而是由事件來觸發、激活從而實現執行
創建觸發器
CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
trigger_body
說明:
trigger_name:觸發器的名稱
trigger_time:{ BEFORE | AFTER },表示在事件之前或之後觸發
trigger_event::{ INSERT |UPDATE | DELETE },觸發的具體事件
tbl_name:該觸發器作用在表名
查看觸發器
- SHOW TRIGGERS
- 查詢系統表information_schema.triggers的方式指定查詢條件,查看指定的觸發器信息:
mysql> USE information_schema;
Database changed
mysql> SELECT * FROM triggers WHERE
trigger_name='trigger_student_count_insert';
刪除觸發器
DROP TRIGGER trigger_name;
觸發器示例
=================先定義一張表:
CREATE TABLE student_info (
stu_id INT(11) NOT NULL AUTO_INCREMENT,
stu_name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (stu_id)
);
CREATE TABLE student_count (
student_count INT(11) DEFAULT 0
);
INSERT INTO student_count VALUES(0);
================然後創建觸發器,在向學生表INSERT數據時,學生數增加,DELETE學生時,學生數減少
CREATE TRIGGER trigger_student_count_insert
AFTER INSERT
ON student_info FOR EACH ROW :這裏要指定有事件變化的表(info表),別指定成了count表
UPDATE student_count SET student_count=student_count+1;
CREATE TRIGGER trigger_student_count_delete
AFTER DELETE
ON student_info FOR EACH ROW
UPDATE student_count SET student_count=student_count-1;
注意這裏的ON TABLE_NAME中的table_name指定的是變化的表和事件,它和trigger_body中的命令並無直接聯繫
body中的SQL語句可以對任何表進行任何操作,和上面ON後面的表並無直接聯繫,那個表只適用於判斷事件的發生,事件發生後就和body無關了(也就是說並非只能針對ON後面的這個表進行操作,body命令沒有限制)
注意點:
- 自定義函數存儲的位置是在mysql.proc表中,這是一個表。
- 函數和存儲過程(本質也是一種函數)的定義可以用交互式方式進行,也可以用非交互式方式先寫到文件內,然後導入即可(數據庫外直接重定向,連接到數據庫內則用source命令)。
- 注意這裏只是定義了函數和存儲過程,而並沒有調用或者執行它們。
- 注意,與示例3中函數體中的局部變量相對應的會話級的全局變量可以在mysql的交互式命令行中用set命令來進行定義賦值;set命令不僅可以定義並賦值用戶自己定義的變量,還可以用來修改系統自身存在的變量的值。
- 不過系統自身的變量的值是否能夠直接在mysql命令行中修改,以及系統變量生效的範圍(global,session也就是這個端口)等等,會在下一章進行詳細介紹。
- 這裏需要注意的就是如果是global類型的變量,只有在mysql服務重啓的時候,它纔會重新恢復到默認值(假設沒寫入配置文件且用set修改了它的值);而session級別的,只要退出了mysql的連接,下次客戶端重新連接mysql服務的時候它都會恢復到默認值(包括另外的終端上連接的也是)。除非將它寫入配置文件中(有相對應的選項)並且重啓mysql服務。
- 另外一點要注意的就是用mysqladmin能夠修改的變量會在重啓mysql服務後才恢復默認值,而不是客戶端mysql連接到服務中後。因爲mysqladmin修改的就是服務器端的配置,如果沒有寫入配置文件,則服務器端重啓之後會恢復到默認值。它和mysql客戶端命令是沒有關係的。
- 注意用set命令定義和賦值自定義變量的時候要在變量名字前面加上@符號,不然會被當做系統變量。這個變量雖然是全局可用的,但它也是出於會話級別的全局,新開一個會話(終端端口)就不能再用了。
- 顯示這個變量的時候要用select @變量名 ;
- 注意show variables [like '系統變量名'] 命令只能顯示系統定義的變量
- 還可以用into命令把聚合函數的結果賦值到自定義變量中:
- select avg(age) form students into @avg_age; select @avg_age;
- 存儲過程就相當於是一部分SQL語句和操作的合集的封裝,和函數很類似(其實本質就是一種特殊的function)
- 函數和存儲過程中的變量使用的的時候(不論是定義的時候用的形參,還是說內部定義的本地變量)都不需要在變量或參數前面加上@符號,只有用到了set命令自定義變量賦值或者外部的自定義變量的時候,才需要在參數名前面加上@符號。
- 注意一點就是表中的字段用set修改賦值的時候也不需要加上@符號,這裏的字段雖然也能夠進行各種計算和條件判斷(where)等,但是字段和變量並不一樣。(參考上面trigger的示例中的set命令,由此想起來這一點的)
視圖
視圖:VIEW,虛表,保存有實表的查詢結果
- 創建方法:
CREATE VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION] - 查看視圖定義:SHOW CREATE VIEW view_name
- 刪除視圖:
DROP VIEW [IF EXISTS]
view_name [, view_name] ...
[RESTRICT | CASCADE]
注意:視圖中的數據事實上存儲於“基表”中,因此,其修改操作也會針對基表實現;其修改操作受基表限制
視圖注意點:
- 因爲視圖創建完之後在數據庫中就像真的表一般無法區分,(此時當然也不可能用show create view view_name的方式來查看,因爲不知道是view 還是 table)
這時候只可以用 show table status like 'view_name'\G; 的方式來判斷這個表到底是視圖還是表格了。 - 視圖可以當做是一個複雜的查詢語句的別名,可以把內連接的查詢結果創建一個視圖,這樣就不用每次輸入很長的的命令來進行內連接查詢了。
- 對視圖的修改如果修改成功了,則對應的原表也會相應的修改;不過對視圖的修改有很多要求,比如必須要是單表,不能有聚合函數等等限制,詳細更多要求以後再研究。