MySQL基礎知識08函數
本文主要內容如下:
1. 函數的語法結構
2. 函數的例子
2.1. 最簡單的函數
2.2. 返回查詢結果的例子
3. 函數與存儲過程的區別
3.1. 參數和返回值的區別
3.2. 函數不允許提交事務
3.3. 函數的特征限制
1. 函數的語法結構
函數過程的語法結構如下:
CREATE
[DEFINER = { user | CURRENT_USER }]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
各個部分的介紹如下:
DEFINER:函數的創建者所屬用戶名。
函數的參數:
proc_parameter:
param_name type
函數的參數只能是IN類型的參數。
參數類型:
type:
Any valid MySQL data type
返回值:
RETURNS type
特征:
characteristic:
COMMENT ‘string‘
| LANGUAGE SQL
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
函數體:
routine_body:
Valid SQL routine statement
其中,
(1)COMMENT定義註釋;
(2)LANGUAGE SQL
(3)DETERMINISTIC
DETERMINISTIC:確定的。
NOT DETERMINISTIC:不確定的。
(4) CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA:
(a)CONTAINS SQL:函數包含SQL語句;
(b)NO SQL: 函數中不包含SQL語句。
(c)READS SQL DATA:函數中包含讀取數據的SQL語句。
(d)MOFIFIES SQL DATA:函數中包含修改數據的SQL語句。
(5)SQL SECURITY { DEFINER | INVOKER }:
假定函數定義者為a,調用者為b,則執行函數時:
DEFINER:先檢查b是否有執行函數權限,再檢查a是否有訪問相關數據表的權限。
INVOKER:先檢查b是否有執行函數權限,再檢查b是否有訪問相關數據表的權限。
2. 函數的例子
2.1. 最簡單的函數
一個最簡單的函數的例子如下:
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns integer
deterministic
return 100;
$$
delimiter ;
使用DETERMINISTIC特征限制,是因為MySQL啟用了Binary Log;在啟用了Binary Log時,如果不使用DETERMINISTRIC等特征限制,則該函數無法創建成功。
調用該函數:
mysql> select sf_p1();
+---------+
| sf_p1() |
+---------+
| 100 |
+---------+
1 row in set (0.00 sec)
2.2. 返回查詢結果的例子
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns integer
deterministic
begin
declare x integer;
select count(*) into x from t1;
return x;
end;
$$
delimiter ;
調用函數:
mysql> select sf_p1();
+---------+
| sf_p1() |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
3. 函數與存儲過程的區別
3.1. 參數和返回值的區別
(1)函數的參數在語法上不允許使用IN和OUT以及INOUT修飾符;在語義上只支持IN類型參數。存儲過程則在語法和語義上均支持IN,OUT和INOUT三種修飾符。
(2)函數必須有返回值定義,即RETURNS語句;函數還必須有至少一條RETURN語句來返回一個值;函數還必須有且僅有一個返回值。存儲過程沒有返回值的概念;存儲過程需要通過OUT或者INOUT類型的參數來返回數據;存儲過程可以定義N個OUT或INOUT類型的參數,N>=0。
3.2. 函數不允許提交事務
函數不允許顯式的提交事務(start transaction和commit等語句),函數也不允許隱式提交事務(truncate table等語句);而存儲過程則沒有這個限制。
以下的函數中存在隱式提交事務的truncate table語句,因此這個函數將無法創建成功。
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns varchar(100)
NOT DETERMINISTIC
begin
truncate table t1;
insert into t1 values ( @@hostname);
insert into t1 values ( uuid());
insert into t1 values ( cast(rand() as char));
return ‘1‘;
end;
$$
delimiter ;
ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function or trigger.
解決辦法:
移除truncate語句。
3.3. 函數的特征限制
在啟用了Binary Log的情況下,函數必須使用某些特征限制,否則該函數將無法創建成功。而存儲過程則不存在這樣的限制。
在啟用了Binary Log的情況下,有可能會存在主從復制,這時必須保證函數的返回值在master和slave中是完全相同的,否則會導致主從數據不一致的問題。
因此,在啟用了Binary Log的情況下,MySQL要求函數必須使用一些特征限制,否則不允許創建該函數。
這些限制可以是以下三種之一:
DETERMINISTIC:確定的值。
NO SQL:函數不執行任何SQL。
READS SQL DATA:函數僅僅讀取一些數據。
如果當前用戶有SUPER權限,則沒有上述限制。
如果全局變量log_bin_trust_function_creators設置為ON,則也沒有上述限制。這個全局變量默認為OFF。
mysql> show variables like ‘%log_bin_trust%‘;
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF |
+---------------------------------+-------+
1 row in set (0.02 sec)
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns varchar(100)
begin
declare x varchar(100);
set x = ‘001‘;
return x;
end;
$$
delimiter ;
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
解決辦法:
增加DETERMINSTIC或NO SQL等特征。
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns varchar(100)
deterministic
begin
declare x varchar(100);
set x = ‘001‘;
return x;
end;
$$
delimiter ;
或者:
drop function if exists sf_p1;
delimiter $$
create function sf_p1()
returns varchar(100)
no sql
begin
declare x varchar(100);
set x = cast( rand() as char);
return x;
end;
$$
delimiter ;
MySQL基礎知識08函數