1. 程式人生 > >MySQL基礎知識08函數

MySQL基礎知識08函數

過程 類型參數 fin hostname cas proc table 數據表 cal

本文主要內容如下:

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)函數的參數在語法上不允許使用INOUT以及INOUT修飾符;在語義上只支持IN類型參數。存儲過程則在語法和語義上均支持IN,OUTINOUT三種修飾符。

(2)函數必須有返回值定義,即RETURNS語句;函數還必須有至少一條RETURN語句來返回一個值;函數還必須有且僅有一個返回值。存儲過程沒有返回值的概念;存儲過程需要通過OUT或者INOUT類型的參數來返回數據;存儲過程可以定義NOUTINOUT類型的參數,N>=0

3.2. 函數不允許提交事務

函數不允許顯式的提交事務(start transactioncommit等語句),函數也不允許隱式提交事務(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的情況下,有可能會存在主從復制,這時必須保證函數的返回值在masterslave中是完全相同的,否則會導致主從數據不一致的問題。

因此,在啟用了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)

解決辦法:

增加DETERMINSTICNO 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函數