MySQL自订函式参数用法in

2013-05-20_091051

这是MySQL 5实力养成暨评量里的8-37.‘在自订函式中下列何项可用来指定参数传递的方式?’

答案:(A) IN

[adsense][/adsense]

在作答这题时ㄚ琪很自然地以为是跟MySQL 预储程序参数用法in, out, inout这类的回答类似,没有确认清楚预储程序跟自订函式的差异就乱填答案了,所以就变成这样。经过确认后,查考MySQL 5.7 Reference Manual :: 13 SQL Statement Syntax :: 13.1 Data Definition Statements :: 13.1.12 CREATE PROCEDURE and CREATE FUNCTION Syntax

MySQL 5.1参考手册 :: 20. 存储程序和函数::20.2.1. CREATE PROCEDURE和CREATE FUNCTION

转译成繁体中文列于下:

CREATE PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body

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

    proc_parameter:
    [ IN | OUT | INOUT ] param_name type

    func_parameter:
    param_name type

type:
    Any valid MySQL data type

characteristic:
    LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

routine_body:
    Valid SQL procedure statement or statements

这些语句建立预储程式。要在MySQL 5.1中建立预储程式,必须具有CREATE ROUTINE权限,并且ALTER ROUTINE和EXECUTE权限被自动授予它的建立者。如果二进制日志功能被允许,您也可能需要SUPER权限,请参阅20.4节,“预储程式和触发程式的二进制日志功能”

预设地,预储程式与当前资料库关联。要明确地把预储程式与一个给定资料库关联起来,可以在建立预储程式的时候指定其名字为db_name.sp_name

如果预储程式名和内建的SQL函数名一样,定义预储程式时,您需要在这个名字和随后括号中间插入一个空格,否则发生语法错误。当您随后使用预储程式的时候也要插入。为此,即使有可能出现这种情况,我们还是建议最好避免给您自己的预储程式取与存在的SQL函数一样的名字。

由括号包围的参数列必须总是存在。如果没有参数,也该使用一个空参数列()。每个参数预设都是一个IN参数。要指定为其它参数,可在参数名之前使用关键词 OUT或INOUT

注意: 指定参数为IN, OUT, 或INOUT 只对PROCEDURE是合法的。(FUNCTION参数总是被认为是IN参数)

RETURNS字句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。

routine_body 包含合法的SQL过程语句。可以使用复合语句语法,请参阅20.2.7节,“BEGIN … END复合语句”。复合语句可以包含声明,循环和其它控制结构语句。这些语句的语法在本章后面介绍,举例,请参阅20.2.8节,“DECLARE语句”20.2.12节,“流程控制构造”

CREATE FUNCTION语句被用在更早的MySQL版本上以支援UDF (自行定义函数)。请参阅27.2节,“给MySQL新增新函数”。 UDF继续被支援,即使现在有了储存函数。UDF会被认为一个外部储存函数。然而,不要让储存函数与UDF函数共享名字空间。

外部预储程式的框架将在不久的将来引入。这将允许您用SQL之外的语言编写预储程式。最可能的是,第一个被支援语言是PHP,因为核心PHP引擎很小,线程安全,且可以被方便地嵌入。因为框架是公开的,它希望许多其它语言也能被支援。

如果程式或线程总是对同样的输入参数产生同样的结果,则被认为它是“确定的”,否则就是“非确定”的。如果既没有给定DETERMINISTIC也没有给定NOT DETERMINISTIC,预设的就是NOT DETERMINISTIC。

为进行复制,使用NOW()函数(或它的同义词)或RAND()函数会不必要地使得一个预储程式非确定。对NOW()而言,二进制日志包括时间戳并被正确复制。RAND() 只要在一个预储程式被内应用一次也会被正确复制。(您可以把预储程式执行时间戳和随机数种子认为强制输入,它们在主从上是同样的。)

当前来讲,DETERMINISTIC特征被接受,但还没有被最佳化程式所使用。然而如果二进制日志功能被允许了,这个特征影响到MySQL是否会接受预储程式定义。请参阅20.4节,“预储程式和触发程式的二进制日志功能”

一些特征提供预储程式使用数据的内在讯息。CONTAINS SQL资料表示预储程式不包含读或写数据的语句。NO SQL资料表示预储程式不包含SQL语句。READS SQL DATA资料表示预储程式包含读数据的语句,但不包含写数据的语句。MODIFIES SQL DATA资料表示预储程式包含写数据的语句。如果这些特征没有明确给定,预设的是CONTAINS SQL。

SQL SECURITY特征可以用来指定预储程式该用建立预储程式者的授权来执行,还是使用使用者的授权来执行。预设值是DEFINER。在SQL:2003中者是一个新特性。建立者或使用者必须由访问预储程式关联的资料库的授权。在MySQL 5.1中,必须有EXECUTE权限才能执行预储程式。必须拥有这个权限的用户要么是定义者,要么是使用者,这取决于SQL SECURITY特征是如何设置的。

MySQL储存sql_mode系统变数设置,这个设置在预储程式被建立的时候起作用,MySQL总是强制使用这个设置来执行预储程式。

COMMENT子句是一个MySQL的延伸,它可以被用来描述 储存程式。这个讯息被SHOW CREATE PROCEDURE和 SHOW CREATE FUNCTION语句来显示。

MySQL允许预储程式包含DDL语句,如CREATE和DROP。MySQL也允许储存程式(但不是 储存函数)包含SQL 交互语句,如COMMIT。储存函数不可以包含那些做明确的和绝对的提交或者做回滚的语。SQL标准不要求对这些语句的支援,SQL标准声明每个DBMS提供商可以决定是否允许支援这些语句。

预储程式不能使用LOAD DATA INFILE。

返回结果包的语句不能被用在储存函数种。这包括不使用INTO给变数读取 列值的SELECT语句,SHOW 语句,及其它诸如EXPLAIN这样的语句。对于可在函数定义时间被决定要返回一个结果包的语句,发生一个允许从函数错误返回结果包的Not(ER_SP_NO_RETSET_IN_FUNC)。对于只可在运行时决定要返回一个结果包的语句, 发生一个不能在给定上下文错误返回结果包的PROCEDURE %s (ER_SP_BADSELECT)。

下面是一个使用OUT参数的简单的预储程式的例子。例子为,在 程式被定义的时候,用mysql客户端delimiter命令来把语句定界符从 ;变为//。这就允许用在 程式体中的;定界符被传递到伺服器而不是被mysql自己来解释。

mysql> delimiter //

mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
    -> BEGIN
    ->   SELECT COUNT(*) INTO param1 FROM t;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)

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

当使用delimiter命令时,您应该避免使用反斜杠(‘\’)字元,因为那是MySQL的 转义字元。

下列是一个例子,一个采用参数的函数使用一个SQL函数执行一个操作,并返回结果:

mysql> delimiter //

mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50)
    -> RETURN CONCAT('Hello, ',s,'!');
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world!  |
+----------------+
1 row in set (0.00 sec)

如果在自订函式中的RETURN语句返回一个类型不同于在函式的RETURNS子句中指定类型的值,返回值被强制为恰当的类型。比如,如果一个函数返回一个ENUM或SET值,但是RETURN语句返回一个整数,对于SET成员集的相应的ENUM成员,从函数返回的值是字串。