10bet网址
MySQL 8.0参考手册
相关的文档10bet官方网站 本手册下载 本手册节选

13.1.17 CREATE PROCEDURE和CREATE FUNCTION语句

创建[定义者=用户)程序sp_name([proc_parameter[,...]]) [特征…]routine_body创建[定义者=用户)函数sp_name([func_parameter[…]])返回类型特征…]routine_bodyproc_parameter: [in | out | inout]param_name类型func_parameterparam_name类型类型任何有效的MySQL数据类型特征{评论'字符串' |语言SQL | [not]确定性|{包含SQL |否SQL |读取SQL数据|修改SQL数据}| SQL安全{定义器|调用器}}routine_body有效的SQL例程语句

这些语句用于创建存储例程(存储过程或函数)。也就是说,服务器知道指定的例程。默认情况下,存储的例程与默认数据库相关联。要显式地将例程与给定数据库关联,请将名称指定为db_name.sp_name当你创建它的时候。

创建函数语句在MySQL中也被用于支持udf(用户定义函数)。看到第13.7.4.1节“用户定义函数的CREATE FUNCTION语句”.UDF可以被视为一个外部存储函数。存储函数与udf共享命名空间。看到第9.2.5节“函数名解析和解析”,用于描述服务器如何解释对不同类型函数的引用的规则。

方法调用存储过程调用声明(见第13.2.1节,“CALL语句”).要调用存储函数,请在表达式中引用它。函数在表达式求值期间返回一个值。

创建过程而且创建函数要求创建程序特权。如果定义者子句存在时,所需的特权取决于用户价值,如在第25.6节,“存储对象访问控制”.如果启用了二进制日志记录,创建函数可能需要超级特权,如在第25.7节“存储程序二进制日志记录”

默认情况下,MySQL自动授予改变日常而且执行例程创建者的特权。控件可以更改此行为automatic_sp_privileges系统变量。看到第25.2.2节“存储例程和MySQL特权”

定义者而且SQL安全子句指定在例程执行时检查访问特权时要使用的安全上下文,如本节后面所述。

如果例程名称与内置SQL函数的名称相同,则会发生语法错误,除非在定义例程或稍后调用它时在名称和下面的括号之间使用空格。出于这个原因,避免为自己的存储例程使用现有SQL函数的名称。

IGNORE_SPACESQL模式适用于内置函数,而不适用于存储例程。在存储的例程名称后面总是允许有空格,无论是否IGNORE_SPACE启用。

括号内的参数列表必须始终存在。的空参数列表()应该使用。参数名不区分大小写。

每个参数都是默认参数。若要为参数指定其他参数,请使用关键字INOUT在参数名称之前。

请注意

将参数指定为,或INOUT仅对a有效过程.对于一个函数,参数总是被视为参数。

一个参数将值传递给过程。过程可以修改值,但当过程返回时,调用方不可见修改。一个参数将过程中的值传递回调用方。它的初始值为,当过程返回时,它的值对调用者是可见的。一个INOUT参数由调用方初始化,可以由过程修改,过程所做的任何更改在过程返回时都对调用方可见。

为每一个INOUT参数中传递一个用户定义的变量调用调用过程的语句,以便在过程返回时获取其值。如果从另一个存储过程或函数中调用过程,还可以将例程参数或局部例程变量作为INOUT参数。如果从触发器内部调用过程,也可以传递新的。col_name作为一个INOUT参数。

有关未处理条件对过程参数的影响的信息,请参见第13.6.7.8节“条件处理和OUT或INOUT参数”

例程参数不能在例程内准备的语句中引用;看到第25.8节,“存储程序的限制”

下面的示例显示了一个简单的存储过程,给定一个国家代码,计算该国家的城市数量城市表的世界数据库。类型传递国家代码参数返回城市计数参数:

mysql> delimiter // mysql> CREATE PROCEDURE citycount (IN country CHAR(3), OUT cities INT) BEGIN SELECT COUNT(*) INTO cities FROM world。WHERE CountryCode =国家;结束//查询OK, 0 rows affected (0.01 sec) mysql> delimiter;mysql>调用城市计数('JPN', @城市);查询OK, 1 row affected (0.00 sec) mysql> SELECT @cities;+---------+ | @ 城市  | +---------+ | 248年  | +---------+ 1行组(0.00秒)mysql >调用citycount(联邦铁路局,@cities);——法国城市查询OK, 1 row affected (0.00 sec) mysql> SELECT @cities;+---------+ | @ 城市  | +---------+ | 40  | +---------+ 1行集(0.00秒)

该示例使用mysql客户端分隔符命令来更改语句分隔符//在定义过程时。这使在过程体中使用的分隔符,要传递给服务器,而不是由mysql本身。看到第25.1节“定义存储程序”

返回子句只能用于函数,这是强制性的。它指示函数的返回类型,函数体必须包含返回价值声明。如果返回语句返回不同类型的值,该值被强制转换为正确的类型。例如,如果函数指定了枚举的价值返回条款,但返回语句返回一个整数,函数返回的值是对应的字符串枚举集合的成员成员。

下面的示例函数接受一个参数,使用SQL函数执行一个操作,并返回结果。在这种情况下,就没有必要使用了分隔符因为函数定义不包含内部语句分隔符:

mysql>返回CHAR(50) DETERMINISTIC RETURN CONCAT(' hello,',s,'!');查询OK, 0 rows affected (0.00 sec) mysql> SELECT hello('world');+----------------+ | 你好(“世界上 ') | +----------------+ | 你好,世界!| +----------------+ 1 row in set (0.00 sec)

参数类型和函数返回类型可以声明为使用任何有效的数据类型。的核对属性前若有字符集规范。

routine_body由有效的SQL例程语句组成。这可以是一个简单的语句,例如选择插入,或用开始而且结束.复合语句可以包含声明、循环和其他控制结构语句。这些语句的语法在第13.6节,“复合语句语法”.在实践中,存储函数倾向于使用复合语句,除非主体由单个语句组成返回声明。

MySQL允许例程包含DDL语句,例如创建而且下降.MySQL还允许存储过程(但不允许存储函数)包含SQL事务语句,例如提交.存储的函数不能包含执行显式或隐式提交或回滚的语句。SQL标准并不要求支持这些语句,它规定每个DBMS供应商可以决定是否允许它们。

返回结果集的语句可以在存储过程中使用,但不能在存储函数中使用。这个禁令包括选择语句中没有var_list子句和其他语句,如显示解释,检查表.对于可以在函数定义时确定返回结果集的语句,a不允许从函数返回结果集发生错误(ER_SP_NO_RETSET).对于只能在运行时确定返回结果集的语句,a过程%s不能在给定的上下文中返回结果集发生错误(ER_SP_BADSELECT).

使用存储例程中的语句是不允许的。当调用例程时,隐式使用db_name执行(当例程终止时撤销)。使例程在执行时具有给定的默认数据库。对数据库中除例程默认数据库之外的对象的引用应使用适当的数据库名称进行限定。

有关存储例程中不允许的语句的其他信息,请参见第25.8节,“存储程序的限制”

有关从用具有MySQL接口的语言编写的程序中调用存储过程的信息,请参见第13.2.1节,“CALL语句”

MySQL存储sql_mode系统变量设置在例程创建或更改时生效,并且总是在此设置生效时执行例程,无论例程开始执行时的当前服务器SQL模式是什么

从调用程序的SQL模式切换到例程的SQL模式发生在实参求值并将结果值赋值给例程参数之后。如果在严格SQL模式下定义例程,但在非严格模式下调用它,则不会在严格模式下为例程参数赋值。如果要求以严格SQL模式分配传递给例程的表达式,则应该在严格模式生效的情况下调用例程。

评论feature是一个MySQL扩展,可以用来描述存储例程。控件显示此信息显示创建过程而且显示创建函数语句。

语言特征表示编写例程所用的语言。服务器忽略这个特性;只支持SQL例程。

考虑一个例程确定的如果它总是对相同的输入参数产生相同的结果,并且不确定性否则。如果既不确定的也不不确定性在例程定义中给出,默认为不确定性.要声明一个函数是确定性的,必须指定确定的明确。

对例行公事性质的评估是基于诚实MySQL不会检查例程是否声明确定的不包含产生不确定结果的语句。然而,错误地声明例程可能会影响结果或影响性能。将一个非确定性例程声明为确定的可能导致优化器做出不正确的执行计划选择,从而导致意想不到的结果。声明一个确定性例程为不确定的可能会导致无法使用可用的优化,从而降低性能。

如果启用了二进制日志记录,则确定的特性影响MySQL接受哪些例程定义。看到第25.7节“存储程序二进制日志记录”

类的例程现在()函数(或其同义词)或RAND ()是不确定的,但它可能仍然是复制安全的。为现在(),二进制日志包含时间戳并正确复制。RAND ()只要在例程执行期间只调用一次,也可以正确复制。(可以将例程执行时间戳和随机数种子视为源和副本上相同的隐式输入。)

有几个特征提供了关于例程使用数据的性质的信息。在MySQL中,这些特征只是建议。服务器不使用它们来约束例程允许执行哪种类型的语句。

  • 包含SQL指示例程不包含读取或写入数据的语句。如果这些特征都没有显式给出,则此值为默认值。这样的陈述的例子有SET @x = 1RELEASE_LOCK (abc),它们执行但既不读也不写数据。

  • 没有SQL表示例程不包含SQL语句。

  • 读取SQL数据指示例程包含读取数据的语句(例如,选择),而不是写数据的语句。

  • 修改SQL数据指示例程包含可能写入数据(例如,插入删除).

SQL安全特性可以定义者调用程序指定安全上下文;也就是说,例程是否使用例程中指定的帐户的特权执行定义者子句或调用它的用户。此帐户必须具有访问例程关联的数据库的权限。默认值为定义者.调用例程的用户必须具有执行特权为之,必为之定义者帐户,如果例程在定义器安全上下文中执行。

定义者子句指定在例程执行时检查访问权限时要使用的MySQL帐户SQL安全定义者的特点。

如果定义者从句是存在的用户值应该是MySQL帐户指定为user_name“@”host_nameCURRENT_USER,或CURRENT_USER ().允许用户值取决于您持有的特权,如中所讨论的第25.6节,“存储对象访问控制”.有关存储例程安全性的其他信息,请参见该部分。

如果定义者子句时,默认定义者是执行创建过程创建函数声明。这与指定是一样的定义者= CURRENT_USER明确。

类定义的存储例程的主体中SQL安全定义者特点,CURRENT_USER函数返回例程的定义者价值。有关存储例程中的用户审计的信息,请参见第6.2.22节,“基于sql的帐户活动审计”

考虑下面的过程,该过程显示MySQL帐户的数量mysql.user系统表:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count() BEGIN SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;结束;

该程序被分配了一个定义者账户的“admin”@“localhost”无论哪个用户定义它。无论哪个用户调用它,它都使用该帐户的特权执行(因为默认的安全特性是定义者).过程的成功或失败取决于调用方是否具有执行对它的特权“admin”@“localhost”选择特权的mysql.user表格

现在假设过程是用SQL安全调用程序特点:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count() SQL SECURITY INVOKER BEGIN SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;结束;

这个过程还有一个定义者“admin”@“localhost”但是在本例中,它使用调用用户的特权执行。因此,过程的成功或失败取决于调用方是否拥有执行它的特权和选择特权的mysql.user表格

服务器处理例程参数的数据类型、创建的本地例程变量声明,或函数返回值如下所示:

  • 检查赋值是否存在数据类型不匹配和溢出。转换和溢出问题在严格SQL模式下会导致警告或错误。

  • 只能分配标量值。例如,这样的语句SET x = (SELECT 1,2)是无效的。

  • 对于字符数据类型,如果字符集时,将使用指定的字符集及其默认排序规则。如果核对属性,则使用该排序规则而不是默认的排序规则。

    如果字符集而且核对如果不存在,则使用例程创建时有效的数据库字符集和排序。为避免服务器使用数据库字符集和排序规则,请提供显式的字符集和一个核对字符数据参数的属性。

    如果更改数据库默认字符集或排序规则,则必须删除并重新创建要使用新的数据库默认值的存储例程。

    的值给出数据库字符集和排序规则character_set_database而且collation_database系统变量。有关更多信息,请参见第10.3.3节“数据库字符集和排序规则”